So I have two arraylists (these are just as an example) [Jeremy, Nick, Noah, Liam, Olivia] and [Elijah, Jeremy, Olivia, Sophia, Charlotte]. How would I go about removing the duplicates "Jeremy" and "Olivia" since they are in the second array. So the output would be firstArr: [Nick, Noah, Liam] and the second arraylist would be unchanged. Here's my method that isn't working.
public static ArrayList<String> removeDuplicates(ArrayList<String> firstArr, ArrayList<String> secArr) {
for (int i = 0; i < firstArr.size(); i) {
for (int p = 0; p < secArr.size(); p) {
if (firstArr.get(i).equals(secArr.get(p))) {
firstArr.remove(i);
p = secArr.size();
}
}
}
return firstArr;
}
CodePudding user response:
Solution was pretty simple, I just had to do i-- after I removed an element since everything moves left 1.
Had to do the prompt this way since it was a assignment for a class, I know there are much better ways.
CodePudding user response:
There are many ways to do this. However, one thing you need to keep in mind is that your loop should not be depending on the collection size if you are going to be modifying it; particularly if you are removing elements. The best way to modify a collection while iterating through it, is to use the collection's Iterator object and use that to determine your loop condition. For example, the code below is equivalent to what you are trying to do:
public static void main(String[] args) {
List<String> firstArr = new ArrayList<>();
firstArr.add("Jeremy");
firstArr.add("Nick");
firstArr.add("Noah");
firstArr.add("Liam");
firstArr.add("Olivia");
List<String> secondArr = new ArrayList<>();
secondArr.add("Elijah");
secondArr.add("Jeremy");
secondArr.add("Olivia");
secondArr.add("Sophia");
secondArr.add("Charlotte");
Iterator<String> firstIter = firstArr.iterator();
while (firstIter.hasNext()) {
String elem = firstIter.next();
Iterator<String> secondIter = secondArr.iterator();
while (secondIter.hasNext()) {
String otherElem = secondIter.next(); // reacquire the iterator after each iteration.
if (elem.equals(otherElem)) {
firstIter.remove(); // safely removes the current item using Iterator#remove()
}
}
}
System.out.println(firstArr);
}
The output is as expected [Nick, Noah, Liam]
As you can see, the loop condition doesn't depend on the collection's size; only in a condition that checks is there are more elements to check. If there aren't any, it simply exits the loop (or won't allow the loop to start altogether). This is the recommended way to iterate while modifying a collection.
I am not saying this is the best way for THIS particular problem, but it is one way of solving this problem AND something you have to know if you ever need to modify a collection while iterating through it. IN FACT. this specific problem can be best solved using Java Streams:
firstArr = firstArr.stream().distinct().filter(Predicate.not(secondArr::contains)).collect.(Collectors.toList));
This expression replaces that entire nested loop structure. Basically, you want to collect the members of the first list that ARE NOT in the second. The reason the predicate is negated is because the filter function will return the matching elements if not negated.
