When you remove an item from the list, the indices change, which is not only causing the IndexOutOfBounds
, but could mean you're removing the wrong values
Now, there are going to be a multitude of ways you might achieve this, for example...
List<String> name = new ArrayList<>(Arrays.asList(new String[]{"a", "b", "a"}));
List<String> discard = new ArrayList<>(25);
for (int outter = 0; outter < name.size(); outter++) {
String match = name.get(outter);
discard.clear();
for (int inner = outter + 1; inner < name.size(); inner++) {
String to = name.get(inner);
if (match.equals(to)) {
discard.add(to);
}
}
if (discard.size() > 0) {
discard.add(match);
name.removeAll(discard);
}
}
System.out.println(name);
This prints...
[b]
This simply collects any matching elements within the inner loop and places them into another List
, which is then passed to the removeAll
method of the original List
after the inner loop has completed
The inner loop starts at the current/outer index (plus 1), as we've already processed all the values before it, so we shouldn't need to continue looping over those items
In theory, you could simply keep adding elements to the discard
List
and do a single removeAll
at the end instead
Updated...
So, I was wondering if there might be another way to approach the problem using Java 8 and it's Stream
support...
List<String> name = new ArrayList<>(Arrays.asList(new String[]{"a", "b", "a"}));
Set<String> allItems = new HashSet<>();
List<String> duplicates = name.stream()
.filter(n -> !allItems.add(n)) //Set.add() returns false if the item was already in the set.
.collect(Collectors.toList());
name.removeAll(duplicates);
So, basically, what this does is it collects all the duplicates in the name
List
and places them into the duplicates
List
(using the allItems
as a temporary holding point).
Then you can simply use it to call removeAll
to remove all the duplicate items.
Now, this relies on the hashcode
and equals
implementations of the objects to work