My question is very basic but I am still not able to figure out how to do this. I have an array of ArrayList like this:
ArrayList<Car>[] cars = new ArrayList[2];
Later in my program I am iterating over that array and I need to remove some objects from the ArrayList. However, since I cannot iterate over a list and remove the elements at the same time, I have decided to clone the array and remove the objects from the ArrayList of the clone. I noticed though, that the clone is referencing the same objects as the ones from the array. Below is some basic example:
ArrayList<Car>[] cars = new ArrayList[2];
cars[0] = new ArrayList<Car>();
cars[0].add(new Car("black"));
cars[0].add(new Car("white"));
cars[1] = new ArrayList<Car>();
cars[1].add(new Car("green"));
cars[1].add(new Car("red"));
ArrayList<Car>[] carClone = cars.clone();
carClone[0].remove(0); // removes the objects from the ArrayList of clone as well as the ArrayList of the "real" array
In the above example you can see that it doesn't just remove the object from the clone, but also from the array. How can I overcome this problem? Any thoughts?
Related
I have a problem with Java: I have a list of integer that I want to put into a specific column and line of an array. For example, in column 1 I want to put [1,2,3] and column 2 [8]...
I tried something - I wanted to put the list into the array and then clear the list to put new values and put in another location of my array etc...
I created an array (RANG) of list and my list (ELEMENTS):
List[] rang=new List[nbSommets];
List<Integer> elements= new ArrayList<>(nbSommets);
I added some numbers and I put into the array ALL my list
rang[???]=elements;
Then, I clear the list to put new values
elements.clear();
But when I clear the list, this clear the list into my array too...
How can I do it ?
Thank you !
When you do rang[???] = elements; you are only assigning a reference to the array elements to rang[???], you are no copying all the values in a new array.
What you have to do is, instead of clearing the elements array, create a new array (new ArrayList<>()) every time.
Replace
elements.clear();
with
elements = new ArrayList<>(nbSommets);
Why elements.clear() clears the original ArrayList object
Because elements is still pointing to the original ArrayList object no matter whether you add it to an array, some other collection or object.
Why elements = new ArrayList<>(nbSommets) will work?
Because it will disconnect the reference to the original ArrayList object and point elements to a new ArrayList.
The problem is that if you create a List elements = new ArrayList(), you create a new object. If you put the list inside your array by rang[???] = elements, now your array contains reference to the List you have created. So your elements variable is pointing to the same object as as rang[???]. You can put it to array by rang[???] = new ArrayList(elements) and you will get a new List, and when you clear elements, the List in array will remain untouched.
I want to add COPIES of data to my List but when I use .add, it adds a reference and not a copy. I'll try to explain what I mean.
List<List<String>> formattedTempMatches = new ArrayList<>();
ArrayList<String> rowFormattedMatches = new ArrayList<>();
rowFormattedMatches.add(matchesArray[0]);
rowFormattedMatches.add(matchesArray[1]);
rowFormattedMatches.add(matchesArray[2]);
formattedTempMatches.add(rowFormattedMatches);
//rowFormattedMatches.clear();
rowFormattedMatches.add(matchesArray[3]);
rowFormattedMatches.add(matchesArray[4]);
rowFormattedMatches.add(matchesArray[5]);
formattedTempMatches.add(rowFormattedMatches);
I've written my code outside of a loop to try to explain myself better. I want to add 3 elements to an ArrayList (of which the elements come from a normal array) then add that ArrayList to a list of lists. When the ArrayList is added to the list, I want to clear it and refill it with 3 more elements and then add it to the next index of the List. The problem is once I clear it, the data is removed from the list. If I don't clear it, the list has 6 elements at each index when there's only supposed to be 3. What should I do?
Apologies for my possibly confusing explanation.
The call of clear() empties the list. As you are using the same instance for each iteration, this will not work. What you can do instead of clearing the list is create a new instance:
List<List<String>> formattedTempMatches = new ArrayList<>();
ArrayList<String> rowFormattedMatches = new ArrayList<>();
rowFormattedMatches.add(matchesArray[0]);
rowFormattedMatches.add(matchesArray[1]);
rowFormattedMatches.add(matchesArray[2]);
formattedTempMatches.add(rowFormattedMatches);
rowFormattedMatches = new ArrayList<>(); // new instance of an empty list
rowFormattedMatches.add(matchesArray[3]);
rowFormattedMatches.add(matchesArray[4]);
rowFormattedMatches.add(matchesArray[5]);
formattedTempMatches.add(rowFormattedMatches);
I have a Class
public class Arc{
...
}
and 2 ArrayList
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
i try to copy rotalar1 to in rotalar2:
rotalar2.addAll(rotalar1);
but i have a problem. if i make any change in rotalar2 , it has an impact on rotalar1 too. I dont want to make a change in rotalar1 :
These rows make problem
rotalar2.get(random1).remove(random3);
rotalar2.get(random2).remove(random4);
Thanks for your time
Iterate over rotalar1 an copy each list of this list to rotalar2. You can make the copy in different ways. In the first example i use the constructor and create a new list with the same elements. Be careful, if you make changes to the Arc objects, this changes will still take effect in both lists. If you dont want this, you have to copy your Arc objects too.
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
for(ArrayList<Arc> list : rotalar1)
{
rotalar2.add(new ArrayList<Arc>(list));
}
This is another way, using Collections.copy(dest,src)
for(ArrayList<Arc> list : rotalar1)
{
ArrayList<Arc> copy = new ArrayList<>();
Collections.copy(copy, list); //or copy.addAll(list);
rotalar2.add(copy);
}
This problem is soved now:
rotalar2.get(random1).remove(random3);
rotalar2.get(random2).remove(random4);
but this will still take effect on both lists:
rotalar2.get(rndList).get(rndArc).set(xvy)
If you want to fix this problem too, you can do something like this:
ArrayList<ArrayList<Arc>> rotalar1 = new ArrayList<ArrayList<Arc>>();
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
for(ArrayList<Arc> list : rotalar1)
{
ArrayList<Arc> tmpList = new ArrayList<>();
for(Arc arcObj : list)
{
tmpList.add(copyOfyourArc); //TODO how do you want to creat a copy of Arc obj?
}
rotalar2.add(tmpList);
}
Method addAll does shallow copy which means it copies all the reference of object (not actual Object) from rotalar1 to rotalar2.
One way, you need to iterate over each object(Arc) and clone
it and add it to new list.
One other way is deep copy using serialization. Example Code
You are not deep copying your list.
The problem is, that your lists contain references to objects. If you copy that (list of) refereces to your second list, both references (the original and the copied one) are pointing to the very same object. Every change applied to the object through the referenc in the second list, will be visible in the first list as well.
To deep copy the collection, you could e.g. iterate over it and manually copy each index.
You should implement your own method to do a deep copy within the Arc class. The method should create a new instance of the object and set all fields(attributes) to the value that the current object has. This method should return a new Object of type Arc that has all the same values as the object trying to be copied. You should then iterate over your arraylist(s) and use your copy method on each object and add the new object to a new arraylist which will be a copy of your original arraylist. Example:
//I don't know the attributes of your Arc class this is just an example
public Arc deepCopy()
{
Arc copyOfArc = new Arc(this.field, this.field2, this.field3, this.field4, etc...);
//if you don't set everything in the constructor then you should use your setters here.
copyOfArc.setField5(this.Field5);
etc...
return copyOfArc;
}
Use this method to iterate over your arraylist and copy each arc object to a new arraylist.
Here is an example of using the deepCopy() method to copy your objects to new arraylist:
ArrayList<ArrayList<Arc>> rotalar2 = new ArrayList<ArrayList<Arc>>();
int counter = 0;
for(ArrayList<Arc> temp : rotalar1)
{
rotalar2.add(new ArrayList<Arc>());
for(Arc temp1 : temp)
{
rotalar2.get(counter).add(temp1.deepCopy());
}
counter++;
}
This will copy arraylist rotalar1 to arraylist rotalar2 with a deepCopy so each arraylist will have its own objects and won't effect each other anymore.
this is my first question on Stack! I'm having a small problem populating a 2d arraylist with arraylists, using the add method. After adding my first arraylist to the 2d arraylist, and attempting to repopulate the SAME 1d arraylist, adding this 1d arraylist again to the 2d arraylist seems to alter the first element of the 2d arraylist I added...
ArrayList<ArrayList<String>> twoDArray = new ArrayList<ArrayList<String>>();
ArrayList<String> oneDArray = new ArrayList<String>();
oneDArray.add("a");
twoDArray.add(oneDArray);
System.out.println("First element in twoDArray: " + twoDArray.get(0)); //prints [a]
twoDArray.add(oneDArray);
oneDArray.clear();
oneDArray.add("b");
twoDArray.add(oneDArray);
System.out.println("First element in twoDArray:" + twoDArray.get(0)); //prints [b]
In practice, oneDArray is actually a local variable inside an iterator, hence why I am attempting to re-use it. I add elements to oneDArray, and when a check returns true, I add oneDArray to twoDArray, empty oneDArray, then continue this process, creating a list of lists.
Would this be to do with twoDArray.get(0) actually holding a pointer to oneDArray, and not it's actual value? If so, how might I work around this issue?
Any help would be much appreciated :)
EDIT: solution to above issue
ArrayList<ArrayList<String>> twoDArray = new ArrayList<ArrayList<String>>();
ArrayList<String> oneDArray = new ArrayList<String>();
oneDArray.add("a");
twoDArray.add(new ArrayList<String>()); // Create new arraylist inside twoDArray
twoDArray.get(0).add(oneDArray.get(0)); // Populate new arraylist rather than hold reference to oneDArray
oneDArray.clear();
oneDArray.add("b");
twoDArray.add(new ArrayList<String>());
twoDArray.get(1).add(oneDArray.get(0));
Yes if you are not creating oneDArray inside the loop and merely clearing it will be overwritting on each iteration, that is why the elements are lost. This is indeed because you have the same reference to the same inner arraylist. You should do ArrayList<String> innerToBeAdded = new ArrayList<>() inside your loop conditional to create a new arraylist.
You say " I add oneDArray to twoDArray, empty oneDArray, then continue this process, creating a list of lists", but what you are really doing is adding the same array multiple times to the twoDArray. Because the exact same array is added multiple times to the twoDArray, when you clear() it, it clears all the values, and when you add a value to oneDArray it will appear in all the places in twoDArray.
Instead of clearing the array, what you should do is create a new instance array: oneDArray = new ArrayList<String>(); This will create a different array as each member of twoDArray
I have a 2D ArrayList. The ArrayList contains 10 ArrayLists. I tried the following code:
This is the main 2D ArrayList. Inside the main ArrayList there are10 ArrayLists:
ArrayList<ArrayList<Items>> arrayList = new ArrayList<ArrayList<Items>>();
Here I tried to create a copy of one of the ArrayList (selectedRow is just a number which says which ArrayList I get)
ArrayList<Items> newList = new ArrayList<Items>(arrayList.get(selectedRow));
After that I create another ArrayList:
ArrayList<Items> changeList = new ArrayList<Items>(it.returnTheNewArrayList(newList,randomItem));
Then in another class I created this method. The purpose of this method is to change an attribute of one of the objects.
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
int randomBin = r.nextInt(50);
for(Items i:a){
if(item==i.itemIds()){
while(randomBin==i.bins()){
randomBin = r.nextInt(50);
}
i.setBin(randomBin);
}
}
return a;
}
Finally, I set the new ArrayList in the 2D ArrayList
arrayList.set(whichList, changeList);
This is the procedure. I have find out, that when I run this procedure, both newList and changeList are the same. In both of these ArrayLists I'm saving the change I did in the method returnTheNewArrayList (I found out it with the debugging). But I want to change only one (the changeList).
What did I do wrong?
The lists contain references to objects. When you call i.setBin(...) that's (presumably) making a change to the object itself.
Each list has an independent copy of the references - so you could remove an element from one list without affecting the other - but they're only references.
Imagine you gave two people clipboards, with the same list of home addresses on. One person went and painted the front door of every house list on their clipboard red, then the second person visited all the same houses. The second person would see red doors, wouldn't they? It's the same thing here. The lists contain references, not objects.
If you want the lists to be completely independent, you'll need to populate them with references to different objects.
EDIT: I've just noticed that you'll also need to change your returnTheNewArrayList method, which actually isn't even creating a new ArrayList in the first place!
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item) {
// Stuff which doesn't change the value of a...
return a;
}
Again, the value of a is just a reference to the list... so when you return the same reference back, you're not returning a new ArrayList at all.
You really need to understand how references and objects work in Java - it's absolutely crucial to working with the language.
Inside of the returnTheNewArrayList method, you first need to clone a. Otherwise you will be modifying the original ArrayList and the original Items. Jon did a nice job of explaining why, so I won't go into it here. Your code could look something like:
ArrayList<Items> clone = new ArrayList<Items>(a.size());
for(Items item: a) clone.add(item.clone());
//modify clone here
return clone;
Since you've written the Items class yourself, you will need to implement the Cloneable interface yourself.
See the clone method's wikipedia page for more information.
The newList and changeList are not the same (not == ) but their content are identical.
Your "Item" objects are passed by reference that's why the two lists references the same Items.
To get a brand new reference you should create a new instance of Item in method returnTheNewArrayList (10 new instances for 10 new references.)
public ArrayList<Items> returnTheNewArrayList(ArrayList<Items> a,int item){
//create a new List
ArrayList<Items> newList = new ArrayList<Items>();
int randomBin = r.nextInt(50);
for(Items oldItem:a){
// make a copy of Item to get a new instance of Item for the new List
Item newItem = new Item(oldItem);
if(item==newItem.itemIds()){
while(randomBin==newItem.bins()){
randomBin = r.nextInt(50);
}
newItem.setBin(randomBin);
}
newList.add(newItem);
}
return newList;
}