Unintended modification in Java - java

I have the following Java code:
List<List<Integer>> list1 = new ArrayList<List<Integer>>(rankings);
for (int i = k + 1; i < rankings.size(); i++) {
for (int j = 0; j < rankings.get(0).size(); j++) {
int index = rankings.get(i).indexOf(j);
list1.get(i).set(index, map.get(j));
}
}
// ...
int newrank = sort(list1.get(i), 0, list1.get(i).size() - 1); // sorts list1
list1 came out sorted, but rankings came out sorted as well. How can I prevent this?
All I wanted to do is to create a duplicate of rankings so that the original copy won't be affected while I sort the temporary, copied array.
Thanks in advance.

new ArrayList<>(list) copies the reference here, not cloning the objects, every amends made in one element will affect both lists.
You can add the elements manually to clone it:
for (List<Integer> intList: rankings) {
List<Integer> someIntCopy = new ArrayList<>();
someIntCopy.addAll(intList);
list1.add(someIntCopy);
}

Related

LinkedList Iteration

I'm new to coding and I'm trying to Iterate a linkedlist. The below is the question: Create a Linkedlist having elements ranging from 1 to 8. I need to reverse the list but with one condition i.e., if the num is given as 2. The output should be produced in the following way: [2,1,4,3,6,5,8,7].
Please find the code below. I tried and able to get the respective answer if num is either 2 or 4.
LinkedList<Integer> list = new LinkedList<>();
for (int i = 1; i < 9; i++) {
list.add(i);
}
int n = 2;
LinkedList<Integer> outList = new LinkedList<>();
while(list.size()>0) {
for(int i=n-1;i>=0;i--) {
outList.add(list.get(i));
list.remove(i);
}
}
System.out.println(outList);
I don't know whether this is the appropriate way. Please help me with the appropriate solution.
The problem I'm facing is if I give num as 3. I'm getting IndexOutOfBoundsException as there are only 2 elements in the last iteration.
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.base/java.util.LinkedList.checkElementIndex(LinkedList.java:559)
at java.base/java.util.LinkedList.get(LinkedList.java:480)
at com.src.User.main(User.java:21)
In your solution, issue would be with last inner iteration. Each iteration is reversal of a block of n elements where as the last step it can be less than n. To consider this, min(n-1,list.size()-1) can be used.
LinkedList<Integer> list = new LinkedList<>();
for (int i = 1; i < 9; i++) {
list.add(i);
}
int n = 4;
LinkedList<Integer> outList = new LinkedList<>();
while(list.size()>0) {
for(int i=Math.min(n-1,list.size()-1);i>=0;i--) {
outList.add(list.get(i));
list.remove(i);
}
}
Reversing the complete list, n is same as length of list:
It can be added to list(like a queue) and then retrieved from the rear side(like a stack). So it doesnt require an index.
LinkedList<Integer> list = new LinkedList<>();
for (int i = 1; i < 9; i++) {
list.addLast(i);
}
int n = 2;
System.out.println(list);
LinkedList<Integer> outList = new LinkedList<>();
while(list.size()>0) {
outList.addLast(list.removeLast());//last element retrieved first
}
System.out.println(outList);

Remove items from custom arraylist implemetation without .remove

I'm working on a custom ArrayList implementation and I have one method where I'm trying to remove an item per conditions from an array such as E[] elements. The array is initialized by doing something like this:
String[] contents = {"chicken", "hippo", "goat"};
ArrayI<String> newarray = new ArrayI(contents);
newarray.chooser(new LongChooser());
It should remove words length 4 or less and return an array like this:
["chicken", "hippo"]
I'm trying not to use any built in methods, like remove(), clone(), arraycopy(), etc. I can't seem to get this to work, I've tried creating a duplicate array and trying to copy elements over like this:
E[] copy = (E[]) (new Object[this.size-1]);
for (int i = 0; i < size; i++) {
if (shorter) {
copy[i] = elements[i];
}
else {
for (int j = i; j<this.size-1; j++) {
elements[j] = elements[j+1];
}
elements[size-1] = null;
size -= 1;
}
for (int i =0; i< copy.length; i++) {
elements[i] = copy[i];
}
size -= 1;
I know this is not the correct way because they aren't the same size array and just returns [longword, longerword, null]. Also I'm pretty sure I should be using the size variable, but it doesn't seem to do much.
How do I get this to work? Thanks.
Create an array to hold the [filtered] results. Its initial size is zero.
Iterate through contents.
If the current element of contents needs to be retained, then
create a temporary array whose length is one greater than the array that holds the results.
copy the results array to the temporary array
set the last element of the temporary array to the current element of contents
assign the temporary array to the results array
Here is the code, using only simple arrays. I presume you can adapt it to your needs. Note that the last line is simply to check the value of newContents. It is not required.
String[] contents = {"chicken", "hippo", "goat"};
String[] newContents = new String[0];
for (String str : contents) {
if (str.length() > 4) {
String[] temp = new String[newContents.length + 1];
for (int i = 0; i < newContents.length; i++) {
temp[i] = newContents[i];
}
temp[newContents.length] = str;
newContents = temp;
}
}
System.out.println(Arrays.toString(newContents));

How to merge two arraylists into one in ascending order

I need to merge two lists into one, in ascending order, not duplicates, and I think my code is really close, I'm just missing something and I can't figure it out. As of now, my code is not working properly in my merge method. I think it has something to do with my loops, but I just can't work around it. My current method prints the new list, but it is not in perfect increasing order. I would appreciate any assistance in figuring out how to make this method print my merged list with ascending order using the contents of l1 and l2.
**Note: I cannot use any built-in array sorting methods.
Thanks!
import java.util.ArrayList;
import java.util.Random;
public class MergeLists {
public static ArrayList<Integer> merge(ArrayList<Integer> l1, ArrayList<Integer> l2){
ArrayList<Integer> mergedList = new ArrayList();
for (int j = 0; j < l1.size(); j++) {
if (l1.get(j) < l2.get(j)) {
mergedList.add(l1.get(j));
mergedList.add(l2.get(j));
} else {
mergedList.add(l2.get(j));
mergedList.add(l1.get(j));
}
}
for (int i = l2.size() - l1.size(); i < l2.size(); i++) {
mergedList.add(l2.get(i));
}
return mergedList;
}
public static ArrayList<Integer> makeRandomIncreasingList(int length) {
ArrayList<Integer> randomList = new ArrayList();
Random rand = new Random();
int inList = rand.nextInt(9) + 1;
int inList2 = rand.nextInt(9) + 1;
for (int i = 0; i < length; i++) {
randomList.add(inList);
inList = inList + inList2;
}
return randomList;
}
public static void doMergeTest() {
ArrayList<Integer> list1 = makeRandomIncreasingList(10);
ArrayList<Integer> list2 = makeRandomIncreasingList(20);
ArrayList<Integer> mergedList = merge(list1, list2);
System.out.println("List 1:" + list1);
System.out.println("List 2:" + list2);
System.out.println("Merged list:" + mergedList);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("Performing merge test #" + (i + 1) + ":");
doMergeTest();
}
}
}
Remove duplicates
arrayList1.remove(arrayList2);
Then merge two arrayList:
arrayList1.addAll(arrayList2);
And Lastly sort the last
collections.sort(arrayList1);
Another way is to use SET: Set doesnt allow duplicates
(HashSet is faster depending on the List implementation class)
Set setmerge = new HashSet(list1);
setmerge.addAll(list2);
list1.clear();
list1.addAll(setmerge);
The first part of your merge() method seems ok, if you modify it a little bit. You need to be going through both lists in parallel, something like
int i = 0, j = 0;
for (; i < l1.size() && j < l2.size();)
And compare individual items and increment indices independently, as in
if (l1.get(i) < l2.get(j)) {
...
i++;
} else
...
j++;
}
The way you were doing it you were literally going in parallel, which is not always correct (think of lists [1 2 2] and [1 1 1] => your merge would look like [1 1 1 2 1 2])
Then, after your "parallel" for-loop (the one where you're iterating through both lists), one of your indices is always going to break your loop because it's at the end of its list. For in-order merging, I usually declare i, j outside the loop (you'll need then after your first for-loop, like above) and then do something like (in your notation):
for (int i1 = i; i1 < l1.size(); i1++) {
mergeList.add(l1.get(i1));
}
for (int i2 = j; i2 < l2.size(); i2++) {
mergeList.add(l2.get(i2));
}
After your first for-loop, you get to the end of exactly one of the lists (someone's going to break the loop), so exactly one of the above loops is going to get executed, and that will contain the remaining items, in order.
Edit: your last for-loop of the merge() method is not correct for your purpose.
You have assumed l2 items are always bigger than l1 items, since you are adding remainder of l2 items in the end of the list. You need to compare them with mergedList items and add them accordingly.

ArrayList of Arraylist a remove function affects all Arraylists

I created an ArrayList of 80 Arraylists. Each ArrayList inside, has the values 1-9.
However, when I delete a value from one of the Arraylists its deleted in all of them.
ArrayList<List> available = new ArrayList<List>();
ArrayList<Integer> possibleValues = new ArrayList<Integer>();
for(int j = 1; j<=9; j++){
possibleValues.add(j);
}
for (int i = 0; i<=80; i++){
available.add(possibleValues);
}
int b = (int) available.get(0).get(2);
available.get(0).remove(0);
String s = available.get(80).toString();
System.out.println(" " + s);
}
Any help is appreciated.
The problem here is that you've added the same ArrayList possibleValues to available 81 times. So, the available list contains 81 references to the same possibleValues list.
Any changes made to the list are visible through any of those 81 references.
If you don't want the changes visible to all references, just one, then you need to make 81 copies of the list to add:
for (int i = 0; i<=80; i++){
available.add(new ArrayList<Integer>(possibleValues));
}
That's because you're adding the same ArrayList to every index of the outer ArrayList . Any change to this ArrayList will automatically result in a change in the other ArrayList .
Nest your loops to always create a new ArrayList or construct a new ArrayList from the already existing one.
Because you are adding the values to same ArrayList. You need to create new Arraylist for 0 to 80 iterations.
for(int j = 1; j<=9; j++){
possibleValues.add(j);// one ArrayList with values.
}
for (int i = 0; i<=80; i++){
available.add(possibleValues); //Here adding same Arraylist 80 times.
}
Try this one
ArrayList<List> available = new ArrayList<List>();
ArrayList<Integer> possibleValues = new ArrayList<Integer>();
for (int i = 0; i<=80; i++){
possibleValues = new ArrayList<Integer>();
for(int j = 1; j<=9; j++){
possibleValues.add(j);
}
available.add(possibleValues);
}
You are adding the same ArrayList 81 times. ArrayList is a reference type, so any change to it will affect all items. It should be:
available.add(new ArrayList(possibleValues));

Java - How to repopulate an arraylist with previously known elements

I have an arraylist populated by four elements, the order of which is random (they are put here by random from another arraylist). I then have a for loop that repeats 10 times, at the end of each repetition I use the clear methods to clear all the elements of the arraylist. However, when I start a new repetition, I would like to repopulate my arraylist with the old (previously worked with) elements that were members of the list in the previous repetition, so that I can use the elements again. And I would like to repeat that until I get out of my 10-repetition for loop. Is there any way to achieve this at all?
Code in addition to my question:
ArrayList<String> answerPegs = new ArrayList<String>();
// add element to ArrayList
ArrayList<String> mySecretAnswer = new ArrayList<String>();
for (int n = 4; n > 0; n--)
{
//populate mySecretAnswer with elements from answerPegs
}
ArrayList<String> clone1 = mySecretAnswer;
for (int q = 0; q < 10; q++) {
for (o = 0; o < 4; o++)
{
}
// called clear() method here
} // END OF 10-ROW LOOP
I would suggest simply having 2 lists - keep a pristine copy of the original list, and then iterate over + clear a copy of that list.
public void doRepetitions(List<Object> original)
{
for( int i=0; i<10; i++ )
{
List<Object> working = new ArrayList<Object>( original );
doStuffWithList(working);
}
}
Edit:
Since you've posted your code, I can give a more specific answer:
You can change your clone to be:
ArrayList<String> clone1 = new ArrayList<String>(mySecretAnswer);
And then move that to be inside your for loop:
for (int q = 0; q < 10; q++)
{
ArrayList<String> clone1 = new ArrayList<String>(mySecretAnswer);
// ....
}
Could you use 2 loops nested and just have the inner loop be the for loop 10 times then clear once at the end

Categories