Can't iterate over objects in a Java for...loop - java

I can't add to my list this query:
// This query always return List<Object[]>
Query buscarRad = AreaPrincipal.em.createNamedQuery("Rad.buscarPorCuil");
buscarRad.setParameter("cuil", cuil);
List<Object[]> listaRad = buscarRad.getResultList();
int i = 0;
for (Object[] filaRad : listaRad) {
// if (filaRad[i].equals(null)) {
if (filaRad[i] != null) {
lvRad.getItems().add(filaRad[i].toString());
}
i++;
}
This is my vector listaRad:
I need all values not null
...but my objects list break at first value and finalize. What's wrong?

You need to use nested loops to iterate over all rows, and then to iterate over all columns within each row. Try this:
for (Object[] filaRad : listaRad) { //for DB rows
for (int i = 0; i < filaRad.length; i++) { //for DB columns within a row
if (filaRad[i] != null) {
lvRad.getItems().add(filaRad[i].toString());
}
}
}
Ideally you should put each column's value in an object's field rather than looping and converting them to toString(). Something like this:
List<MyDbRow> rows = new ArrayList<>();
for (Object[] filaRad : listaRad) {
MyDbRow row = new MyDbRow();
row.setId(fileRad[0]); //may require casting
row.setName(fileRad[1]);
rows.add(row);
}

See if this works for you. First you can put all elements at one level in an Object array list. After that you can loop through that list and check for null elements.
// This query always return List<Object[]>
Query buscarRad = AreaPrincipal.em.createNamedQuery("Rad.buscarPorCuil");
buscarRad.setParameter("cuil", cuil);
List<Object[]> listaRad = buscarRad.getResultList();
List<Object> finalList = new ArrayList<>();
int i = 0;
for (Object[] filaRad : listaRad) {
finalList.add(Arrays.asList(filaRad));
}
for(Object o : finalList){
if (o != null) {
lvRad.getItems().add(o.toString());
}
}
In java 8 you can do like this assuming that lvRad.getItems() is a list
itself
lvRad.getItems().addAll(finalList.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList()));

Related

Using an Iterator inside a for loop to remove elements from an ArrayList

I have an ArrayList of objects that have a version number as a field. I want to do some work on that ArrayList, but I only want the most recent version of the object. I was thinking of coding as such:
ArrayList<ObjectVO> ObjectList = getObjectList();
for(ObjectVO myVO : ObjectList) {
Iterator<ObjectVO> iter = ObjectList.iterator();
while(iter.hasNext()) {
ObjectVO checkVO = iter.next();
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
iter.remove();
}
}
}
}
Is this valid? I don't know if the fact that we are in a for loop originally would break the mutability of the ArrayList at runtime.
No, this won't work. iter.remove() will cause the out for loop to fail with ConcurrentModificationException.
Instead of doing this, you can do this with indexed for loops, and a BitSet to keep track of things you want to remove:
BitSet toRemove = new BitSet();
for (int m = 0; m < ObjectList.size(); ++m) {
if (toRemove.get(m)) continue;
ObjectVO myVO = ObjectList.get(m);
for (int c = 0; c < ObjectList.size(); ++c) {
if (toRemove.get(c)) continue;
ObjectVO checkVO = ObjectList.get(c);
if(myVO.getID().equals(checkVO.getID()) {
//they are the same object ID. Check the version number, remove it lower
if(myVO.getVersion() > checkVO.getVersion()) {
toRemove.set(c);
}
}
}
}
This is basically your code, but it doesn't do the removal yet. Then you can sweep through the list after and remove them:
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (!toRemove.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
The point of using a BitSet like this is that removal from an ArrayList is inefficient if you are removing from anywhere other than the end, because it requires all of the elements "to the right" of the element you remove to be shuffled along by one position. The loop with the set/get and clear allows you to only move each of the retained elements once.
You can do a bit better than the quadratic loop, though, if you group the list elements by things with the same ID: then you don't need to keep on checking the entire list:
BitSet toKeep = new BitSet();
IntStream.range(0, ObjectList.size())
.mapToObj(a -> a)
.collect(
groupingBy(a -> ObjectList.get(a).getID(),
maxBy(comparingInt(a -> ObjectList.get(a).getVersion()))))
.values()
.forEach(a -> toKeep.set(a));
int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
if (toKeep.get(src)) {
ObjectList.set(dst++, ObjectList.get(src));
}
}
ObjectList.subList(dst, ObjectList.size()).clear();
Assuming you have the memory, rather than do an O(N^2) operation, you could do this more efficiently (O(N)) by using a Map to track the newest Version for each Id. One pass tracks the newest version for each Id, and the second removes elements which are not the latest.
Map<Integer, Thing> newestById = new HashMap<>();
for (Thing thing : list) {
newestById.merge(thing.id, thing, (a,b) -> a.version > b.version ? a : b);
}
list.removeIf(thing -> thing != newestById.get(thing.id)); }
Depending on your use case, you might even be able to store your data in a Map instead of a List, and check if the version is the latest before adding it to the Map.
As the other answers have discussed this won't work. You have three options as I see them, trading memory for CPU cycles/flexibility. I've used Integer instead of ObjectVO in my examples, but it'll be trivial to swap them.
Option 1 - moderate memory, single-pass of the array
Track the highest ID you've seen and populate an ArrayList with new items as they meet the criteria. When you encounter a new higher ID, throw away the ArrayList and create a new one:
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
ArrayList<Integer> allObjectsMatchingId = new ArrayList<>();
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
allObjectsMatchingId = new ArrayList<>();
} else if(currentObject == bestId) {
allObjectsMatchingId.add(currentObject);
}
}
return allObjectsMatchingId;
Option 2 - more expensive memory, single-pass of the array, most flexible.
For each ID you see, create an ArrayList and store it against a map. This allows you to easily change the criteria about what ID you want to keep.
ArrayList<Integer> objectList = getObjectList();
Map<Integer, ArrayList<Integer>> objectsById = new HashMap<>();
for(Integer currentObject : objectList) {
ArrayList<Integer> listForId = objectsById.get(currentObject);
if(listForId == null) {
listForId = new ArrayList<Integer>();
}
listForId.add(currentObject);
objectsById.put(currentObject, listForId);
}
Integer bestId = -1;
for(Integer i : objectsById.keySet()) {
if(i > bestId) {
bestId = i;
}
}
return objectsById.get(bestId);
Option 3 - no additional memory aside from id, two-passes of the array.
Search through the ArrayList for the highest ID, then filter the array to only elements that pass that filter.
This is the closest to your current implementation, the difference being that you do them in separate steps. This reduces complexity from O(N^2) to O(N), and is valid as you aren't modifying the ArrayList while iterating it. You could use a Stream here to filter instead of an iterator if you're Java 8 compatible. See Java: Efficient ArrayList filtering?
ArrayList<Integer> objectList = getObjectList();
Integer bestId = -1;
for(Integer currentObject : objectList) {
if(currentObject > bestId) {
bestId = currentObject;
}
}
Iterator<Integer> iter = objectList.iterator();
while(iter.hasNext()) {
if(iter.next() != bestId) {
iter.remove();
}
}
Why not use Java Streams to solve this:
Collection<ObjectVO> result = objectList.stream()
.collect(Collectors.toMap(ObjectVO::getID, Function.identity(),
BinaryOperator.maxBy(Comparator.comparing(ObjectVO::getVersion))))
.values();
This creates a map which contains the max version for each id. Then you can just use Map.values() to get the object list.
If you need a List or an ArrayList you can just use new ArrayList<>(result).

Filter List<Object[]> to retain consistent values

First, I had a list with several arrays of type Object, e.g.:
Object[] arr1 = new Object[] {"FIM4R1500030", BigInteger.valueOf(5272456l), "A10328E00074531842"};
Object[] arr2 = new Object[] {"FIM4R1500031", BigInteger.valueOf(886445384123l), "A10328E00074531842"};
final List<Object[]> arrs = Arrays.asList(arr1, arr2);
Then, I wrote a logic that filters them to retain the consistent values and fills in null for the inconsistent ones. The result looked something like this:
List[
Object[][null,null,"A10328E00074531842"],
Object[][null,null,"A10328E00074531842"]
]
Now, my problem is that the logic for this turned out rather convoluted and difficult to read and I am not sure whether I can live with it. Also, I don't really want to start writing a fully-blown utility class, since the functionality seems small for this. Here is my code:
final Predicate<Integer> isConsistant = index -> {
for (Object[] arr : arrs) {
if (!arr[index].equals(arrs.get(0)[index])) {
return false;
}
}
return true;
};
List<Object[]> filtered = arrs.stream().map(arr -> {
Object[] returnList = new Object[arrs.get(0).length];
for (int i = 0; i < arrs.get(0).length; i++) {
if (isConsistant.test(i)) {
returnList[i] = arrs.get(0)[i];
} else {
returnList[i] = null;
}
}
return returnList;
})
.collect(toList());
My question is, how to make this simpler!
Why do you want a List<Object[]> as the result of your filter? If I understood your problem well, all the Object[] inside that list will look the same. So the code could just be:
Object[] filtered = IntStream.range(0, arrs.get(0).length)
.mapToObj(i -> arrs.stream().allMatch(arr -> arr[i] != null && arr[i].equals(arrs.get(0)[i])) ? arrs.get(0)[i] : null)
.toArray();
The problem with this code is not that it's too complex, but that it is unnecessarily slow: for each pair of (row, column) of arrs you walk the entire array again, trying to determine if all values in the column are equal to each other. Essentially, you are running isConsistant on the same column N times - once for each row, even though the predicate always returns the same value. This may be very significant when the number of rows is high.
The process always ends up with N identical rows, so you might as well construct that row once, and make N copies of it:
Object[] row = new Object[arrs.get(0).length];
for (int i = 0 ; i != arrs.get(0).length ; i++) {
if (isConsistant.test(i)) {
row[i] = arrs.get(0)[i];
}
}
// Now we make N copies of that row:
List<Object[]> filtered = new ArrayList<Object[]>();
for (int i = 0 ; i != arrs.length() ; i++) {
filtered.add((Object[])row.clone());
}
If you are not planning on modifying elements of filtered, you may skip the clone part, and insert the same object N times.

Accessing multi dimensional ArrayList values

I am getting 3 columns for each row from mysql table by using ResultSet. I am not sure about the number of rows I will get by using query. To store those rows I am using ArrayList as given code below:
while (rs.next())
{
String[] row = new String[numcols];
for (int i = 0; i < numcols; i++)
{
row[i] = rs.getString(i + 1);
}
rowsList.add(row);
}
rs.close();
When I debugged the code I found columns values are present in the ArrayList. Now I am unable to access the columns values because rowsList.get(index) will return only value at specific index but I have further 3 more values at that index how to access those values.
List.get() in your case will return a String array: String[]. You can access the elements of an array by using the [] index operators:
String[] row = rowList.get(0);
for (int i = 0; i < row.length; i++)
System.out.println(row[i]);
// Or you can use the enhanced for to loop through the array:
for (String s : row)
System.out.println(s);
If you want to process all rows:
for (String[] row : rowList) {
// Process row
for (String s : row) {
// Do something with the string
}
}
I would like to suggest you to learn about List.
And the second would be to create a class that holds everything that comes from your query.
And finally save each object of the class to the array.
Example
Suppose you get id, name and address columns from your query
Create a class
public class YourClass{
int id;
String name, address;
//create getters and setters or use a constructor
//example of setter to set field id
public void setId(int id){
this.id = id;
}
}
And then while retrieving the records from query, create an object of your class and set the columns as field of your class as follow:
YourClass anObject = new YourClass();
anObject.setId(id);// get similar columns from query
anObject.setName(name);
And finally add the object to the ArrayList as below:
yourArrayList.add(anObject);
To take care of multiple number of records you need to keep these code inside the while loop
And define your List before while loop as follow:
List<YourClass> yourArrayList = new ArrayList<YourClass>();
And I think this is the best approach as it uses OOP that you should begin using instead of using bare array.
you would want to specify what object is in the list. to achieve this make your List to List<String[]> rowsList = new ArrayList<String[]>();
then use your while loop
while (rs.next())
{
String[] row = new String[numcols];
for (int i = 0; i < numcols; i++)
{
row[i] = rs.getString(i + 1);
}
rowsList.add(row);
}
rs.close();
when you access each item in the list it will always return a String[] which you can iterate to get the values.
for(int i = 0 ; i< rowsList.size() ; i++){
rowsList.get(i);//will return a String[]
}
OR
for(String[] rows : rowsList){
//iterate the rows
}

How to iterate inside an array of object containing multiple fields?

I have a resultList which fetches result from a JPQL query that queries multiple tables as described :
Query query = em.createQuery("SELECT protein.gid,protein.uniProtAccession,protein.name,protein.ECNumber,ttdtarget.uniProtID,ttdtarget.gid FROM Protein protein,TtdTarget ttdtarget WHERE protein.uniProtAccession = ttdtarget.uniProtID");
List resultList = query.getResultList();
Note: I am restricting the size of resultset to 5 right now, just for debugging. I want to get the values returned inside each object from the resultList, which basically is an array of objects.
So far I have tried iterating upto the objects but can't access the inner values.
for (int i = 0; i < resultList.size(); i++)
{
System.out.println("->"+resultList.get(i));
}
Output:
->[Ljava.lang.Object;#141ab9e
->[Ljava.lang.Object;#6a15ca
->[Ljava.lang.Object;#bcb654
->[Ljava.lang.Object;#1664b54
->[Ljava.lang.Object;#db953c
And here is the variable's output from debug:
So my question is how to access those values inside the object.
The result is List<Object[]>, so cast to that. So a list, where each element is an array of values. You must then cast each value to its type (which you know beforehand).
If you simply want to iterate and print:
List<Object[]> resultList = (List<Object[]>) query.getResultList();
for (Object[] array : resultList) {
for (Object field : array) {
System.out.println("->"+field);
}
}
Alternatively, you can create a new class which has these exact fields, make its constructor accept all of the values, and use it in the query: SELECT new Foo(.....) FROM... There you can use the generic alternative of em.createQuery(..) that returns TypedQuery
You don't have a List of Objects, it is a List of Objectarrys
List<Object[]> resultList = (List<Object[])resultList;
for (int i = 0; i < resultList.size(); i++)
{
System.out.print("protein.gid ->"+resultList.get(i)[0]);
System.out.println("protein.uniProtAccession ->"+resultList.get(i)[1]);
}
List<Object[]> resultList = query.getResultList();
for (Object[] objects : resultList)
{
for (Object object : objects)
{
System.out.println(object)
}
}
Your result form the query is array of objects.
List resultList = query.getResultList();
for(Object result : resultList) {
Object[] results = (Object[]) result;
for(Object res : results) {
System.out.println(res);
}
}
Or you can go with Bozho solution and create new direct from query.
You can create a new class with the exact fields you need and use a TypedQuery
TypedQuery<CustomClass> query = em.createQuery("" /* Query String */, CustomClass.class);
List<CustomClass> resultList = query.getResultList();
foreach (CustomClass result : resultList){
// Need to override method toString() in CustomClass
System.out.println("->" + result);
}
I'm tempted to suggest nesting a for loop:
for (int i = 0; i < resultList.size(); i++)
{
for(int j = 0; j < resutList.get(i).size(); j++){
System.out.println("->"+resultList.get(i).get(j));
}
}

java: converting DynaBean (apache-commons-beanutils) to List

I use apache-commons-beanutils DynaBean class in order to fetch rows from a database and to handle them outside of the mysql function.
is there a way to convert a DynaBean to a List without iterating through each row and manually creating the list ?
thanks!
so far I didn't get any answers so I wrote the function that iterates through the rows and creates an ArrayList of HashMap type (String, Object).
public ArrayList<HashMap<String,Object>> convertDynaBeanListToArrayList(List<DynaBean> theList) {
ArrayList<HashMap<String,Object>> result = new ArrayList<HashMap<String,Object>>();
DynaProperty[] dynaProperties = null;
for (Integer i=0;i<theList.size();i++) {
DynaBean row = theList.get(i);
HashMap<String,Object> resultRow=new HashMap<String,Object>();
// each raw got the same column names, no need to fetch this for every line
if (dynaProperties == null) {
dynaProperties = row.getDynaClass().getDynaProperties();
}
for (Integer j=0;j<dynaProperties.length;j++) {
String columnName=dynaProperties[j].getName();
resultRow.put(columnName, row.get(columnName));
}
result.add(resultRow);
}
return result;
}

Categories

Resources