I have two lists containing the same type of objects. Each object has an int, a string and some other stuff where the int is its index.
Here is the object that both lists are holding:
public class ListElement
{
private int index;
private String data;
private String some;
private String other;
private String stuff;
// gets, sets...
}
What i want is to take List A's index and "some other stuff" and replace its string "data" with the one from List B. The one it takes from List B should match the index of List A. I hope this is understandable.
EDIT: It should be noted that the index int inside the object has nothing to do with the actual position of the object in the list. Its for other porpuses
UPDATE: You mentioned that the index field of your ListElement has no relationship with its actual place in its containing List.
You just happen to have a field with a random name that you want to compare both list on (join on). This solution uses nested loops to compare every element in one list with every element in the other list.
for (int iA = 0; iA < listA.size(); iA++) //iterate over listA
{
ListElement currentElement = listA.get(iA);
for (int iB = 0; iB < listB.size(); iB++) //iterate over listB
{
ListElement other = listB.get(iB);
if (other.index == currentElement.index) //compare the elements
{
//do stuff
currentElement.setData(other.getData());
break; //if only want first match
}
}
}
Assuming your both list have the same number of elements, you could do something like:
ListElement sourceElement, destElement;
for (int i =0; i<list1.size(); i++) {
sourceElement = list1.get(0);
destElement = list2.get(0);
sourceElement.setData(destElement.getData());
...
}
The first idea is probably not the brightest but I'll come to that later.
For (ListElement e : ListA) {
For (ListElement le : ListB) {
if (e.getIndex() = le.getIndex()) {
e.setData(le.getData());
}
}
}
So this is my first shot for what you wrote, but it's probably not the easiest way. To make it simpler and faster you could implement the interface Comparable and use sort, i this case you access the List elements by the index in ListElement (assuming you assure the indices are complete from 1..n).
My favored solution would be to use some kind of maps to store the index as key, and the ListElement as value, then it's just MapA.get(i).setData(MapB.get(i).getData()) This is fool-prove, as long as for every item in MapA there is an according item in MapB with the same index.
If you want to match on the index field on the ListItem object, try this:
for (ListItem listItemA : listA) {
for (ListItem listItemB : listB) {
if (listItemB.getIndex() == listItemA.getIndex()) {
listItemA.setData(listItemB.getData());
}
}
}
If you're interested in matching based on index within the List objects, try
for (int i = 0; i < listA.size(); i++) {
listA.get(i).setData(listB.get(i).getData());
}
Related
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).
For Example I have ArrayList with Objects.
This objects have some field - pictureName.
One of them really have picture name (lets name them "1st type"), other have just an empty string (2nd type).
size of arrayList = M and can change.
Amount of 1st and 2nd-type objects can be different.
I need to get equal or close to equal amount of 1st type objects and 2nd type objects and add them into another (empty) arraylist. Size of this arraylist is N, and N<=M.
What is the better way to do this?
UPD: I can't set the size of new ArrayList. I just can find out this number (user sets it). But N<=M is always true
Edit
OP clarified their requirements so I have updated my code. I still begin by sectioning into two lists as below, but then I build the final list as follows:
Iterator<MyObject> namesIterator = withNames.iterator();
Iterator<MyObject> noNamesIterator = noNames.iterator();
while (newList.size() < userDefinedSize) {
if (namesIterator.hasNext()) {
newList.add(namesIterator.next());
}
if (noNamesIterator.hasNext() && newList.size() < userDefinedSize) {
newList.add(noNamesIterator.next());
}
}
Original
My strategy is to iterate over the original list and bucket the objects by whether they have a pictureName or not. Then create a new list, and add to that list from my buckets until I use up all the elements in the smallest bucket.
private void myMethod() {
List<MyObject> original = /* your code here */
List<MyObject> withNames = new ArrayList<>();
List<MyObject> noNames = new ArrayList<>();
for (MyObject o : original) {
if (o.pictureName != null) {
withNames.add(o);
}
else {
noNames.add(o);
}
}
int size = Math.min(withNames.size(), noNames.size());
List<MyObject> newList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
newList.add(withNames.get(i));
newList.add(noNames.get(i));
}
// now you have the same number of named and unnamed objects in `newList`
}
I am trying to develop a method which receives a List of ArrayList and classify the array list inside it based on the object value. Then, return array list that contains the objects have 1 in their FirstChoice.
the data structure in my code is that
the List has n number of ArrayList, the ArrayList has 24 objects. each object has 3 elements and FirstChoice is one of these elements.
The problem of my code is the output not as i expect , it seems to be just stick with one value and repeat it for the whole list. could you please help me to fix that
ArrayList<HH> TestMethods(List<ArrayList<HH>> s) {
ArrayList<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (int i = 0; i < d.size(); i++) {
if (s.get(i).get(i).FirstChoice == 1) {
scenario.add(s.get(i).get(i));
}
}
}
return scenario;
}
The problem in your code is that when you are looping over the list s, you are actually never using the current element d.
Some other comments on your code:
Prefer returning a List instead of an ArrayList.
Name your methods and variables according to Java naming conventions (testMethods instead of TestMethods, firstChoice instead of FirstChoice)
Be consistent in the way you write loops: use foreach or an index but keep to the same style.
List<HH> testMethods(List<ArrayList<HH>> s) {
List<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (HH hh : d) {
if (hh.firstChoice == 1) {
scenario.add(hh);
}
}
}
return scenario;
}
Your mistakes are on these lines if (s.get(i).get(i).FirstChoice == 1) { and scenario.add(s.get(i).get(i)); as you aren't actually user inner list d.
You're referencing the i'th element of the i'th list of s, when I think you want the i'th element of d where d is a list from s.
ArrayList<HH> TestMethods(List<ArrayList<HH>> s) {
ArrayList<HH> scenario = new ArrayList<HH>();
for (ArrayList<HH> d : s) {
for (int i = 0; i < d.size(); i++) {
int item = d.get(i).FirstChoice;
if (item == 1) {
scenario.add(item);
}
}
}
return scenario;
}
I have one arraylist and one String array. The String array contains IDs and the Array List contains the ids and information related to those Ids. This ArrayList is in an undesirable order. I have a String Array of the Ids in the order in which I want them to be in the ArrayList.
Semi-Pseudocode Example:
ArrayList<MyObject> myList = new ArrayList<MyObject>();
for (every username)
{
myList.add(new MyObject(id, username, content, country);
}
String[] ids = new String[myList.size()];
...Ids are added and sorted here...
I now have a list of Ids, in their correct order. Each Id in "myList" corresponds to an Id in the "ids" String Array. I want to sort "myList" based on the order of it's corresponding id in the "ids" String Array.
How can I re-sort my ArrayList in such a way?
Eg. if in Array list I have:
1. 123, Bob, test, USA
2. 1234, Vladimir, test, USA
3. 12345, Yoseph, test, USA
and in the String[] I have:
1. 1234
2. 123
3.12345
How can I reorder the ArrayList based off of the Ids in the String Array, thus producing:
1. 1234, Vladimir, test, USA
2. 123, Bob, test, USA
3. 12345, Yoseph, test, USA
One solution would be to iterate over the ids array, and search the object for the current id in the array. We know its final (desired) position: it is the index in the array (because we want the list sorted just like the array), so we can move this element to its final place in the list (we do this by swapping it with the element being at the position we're at currently in the array).
for (int i = ids.length - 1; i > 0; i--) { // Downward for efficiency
final String id = ids[i];
// Big optimization: we don't have to search the full list as the part
// before i is already sorted and object for id can only be on the remaining
for (int j = i; j >= 0; j--) // NOTE: loop starting at i
if (id.equals(myList.get(j).getId()) {
Collections.swap(myList, j, i);
break;
}
}
Note: the for loop omits the last element (i==0) because if all other elements are in place, the last is also in (its) place.
This is much faster than creating a comparator and using a sorting algorithm (which Collections.sort() does for example) because the order of the elements is already known (defined by the ids array) and sorting algorithms (no matter how smart the algorithms are) can only use the info [less | equals | greater] returned by comparators.
You could write your own Comparator based on the index in the array:
public class MyObjectComparator implements Comparator<MyObject> {
private List<String> ids;
public MyObjectComparator(String[] ids) {
this.ids = Arrays.asList(ids); // Copying the array would be safer
}
public int compare (MyObject obj1, MyObject obj2) {
return Integer.compare(ids.indexOf(obj1), ids.indexOf(obj2));
}
}
// Use it:
Collections.sort (myList, new MyObjectComparator(ids));
You simply need a comparator:
List<String> ids = Arrays.asList(array);
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return Integer.compare(ids.indexOf(o1.getId()), ids.indexOf(o2.getId()));
}
});
Of course, if your list is large, this will be very inefficient. So you'd better build a Map<String, Integer> containing each ID as key and its position in the array as value, and use this map inside the comparator:
Map<String, Integer> idPositions = new HashMap<>();
for (int i = 0; i < array.length; i++) {
idPositions.put(array[i], i);
}
Collections.sort(list, new Comparator<MyObject>() {
#Override
public int compare(MyObject o1, MyObject o2) {
return idPositions.get(o1.getId()).compareTo(idPositions.get(o2.getId()));
}
});
crs_rawStepSeqNum: Your arrayList
crs_rawStepSeqNum: Same arrayList
for(int x =0;x<crs_rawStepSeqNum.size();x++)
if((x+1) < crs_rawStepSeqNum.size()) {
if (Integer.parseInt(crs_rawStepSeqNum.get(x)) > Integer.parseInt(crs_rawStepSeqNum.get(x + 1))) {
crs_rawStepSeqNum.set(x, crs_rawStepSeqNum.get(x + 1));
crs_rawStepSeqNum.set(x + 1, crs_StepSeqNum.get(x));
crs_StepSeqNum.clear();
crs_StepSeqNum.addAll(crs_rawStepSeqNum);
x=0;
}
}
}
considering there is a structure as described in http://prohost.lt/stack/q.png
In the main arrayList we have n elements(sub arrayLists) (as for image we can consider n=3).
How to make a dynamic loop thru all sub arrayLists so as to get:
sarraylist1.get(0), sarrayList2.get(0), .. sarraylistN.get(0)
In case n=3 it would be
for(sarraylist1){
for( sarraylist2){
for(sarraylist3){
element from every list
}
}
}
Maybe I misunderstood what you were asking, but would something as simple as this not work?
List<List> lists = new ArrayList<List>();
for(List l : lists){
for(List subl: l)
Object o = subl.get(0);
}
Based on your scheme of the image, you can also do it with the "for while loop":
for (int mainArrayElements = 0; mainArrayElements < listOfLists.size(); mainArrayElements++) {
List arraysInMain = ((List)listOfLists.get(mainArrayElements));
for (int subArrayElements = 0; subArrayElements < arraysInMain.size(); subArrayElements++) {
List deepArray = ((List)listOfLists.get(subArrayElements));
for (int innerArrayElements = 0; innerArrayElements < deepArray.size() ; innerArrayElements++) {
System.out.println(deepArray.get(innerArrayElements));
}
}
}
But as mentioned before, recursion would be a really great combo to knock out the problem :).
Best regards.
If I understood correctly, you have one List containing n Lists for which you want to get the first, second and so on, element of each list. This code does that.
for (int i = 0; i < highestSizeOfChildrenList; i++) {
List<Object> lstOfItemInChild = new Arraylist<Object>();
for (List childList : mainList) {
if (i < childList.size()) {
lstOfItemInChild.add(childList.get(i));
}
}
// lstOfItemInChild now contains all the element i of the sub arrays
}
You will need to know the size of the biggest subList to get all the elements of that list, that is what highestSizeOfChildrenList represents.
After watching your comment I suggest you to use recursive approach to solve your problem.
public void recursiveCall(ArrayList list)
{
for ( Object obj : list)
{
if (obj instanceOf ArrayList)
{
recursiveCall((ArrayList)obj);
}
else
{
System.out.print(obj);
}
}
}