for (int i=0; i<name.size(); i++)
{
for (int j = 1; j<name.size(); j++)
if (name.get(i).equals(name.get(j)))
{
name.remove(i);
name.remove(j);
j=j-1;
}
}
最初,name
是一个包含400个元素的ArrayList
。我想删除重复的元素。我不知道为什么我的编译器一直在给我
java.lang.IndexOutOfBoundsException:Index:1,Size:1
请注意,我正在尝试删除重复的对。在arraylist中只能有两个相同的元素。不可能有3个或更多。
答案 0 :(得分:3)
我认为这很有效。你有2个小错误。
for (int i = 0; i < name.size(); i++)
{
for (int j = i + 1; j < name.size(); j++) // j needs to start at i + 1 not 1.
if (name.get(i).equals(name.get(j)))
{
name.remove(j); // You need to remove at the higher index
name.remove(i); // first, because items are shifted left.
j = j - 1;
}
}
答案 1 :(得分:0)
当您从列表中删除某个项目时,索引会发生变化,这不仅会导致IndexOutOfBounds
,还可能意味着您要删除错误的值
现在,您可以通过多种方式实现这一目标,例如......
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);
这打印......
[b]
这只是收集内部循环中的所有匹配元素并将它们放入另一个List
,然后在内部循环完成后将其传递给原始removeAll
的{{1}}方法
内部循环从当前/外部索引(加1)开始,因为我们已经处理了之前的所有值,因此我们不需要继续循环这些项
理论上,您可以直接向List
discard
添加元素,并在最后执行单个List
<强>更新... 强>
所以,我想知道是否有其他方法可以使用Java 8及其removeAll
支持来解决问题......
Stream
所以,基本上,它的作用是收集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);
name
中的所有重复项,并将它们放入List
duplicates
(使用List
}作为临时控制点。)
然后,您只需使用它来调用allItems
即可删除所有重复的项目。
现在,这取决于要运行的对象的removeAll
和hashcode
实现
答案 2 :(得分:0)
我不会从您正在迭代的列表中删除项目。可以调整索引,但这会使代码难以阅读。
相反,您可以使用Iterator
,它会为您处理indice调整。
这是一个简单的例子来说明这个概念(我在某种程度上简化了你的问题,在这种情况下我没有检查重复,只是“bob”):
ArrayList<String> names = getNames(); // populate the list with some names
Iterator<String> iterator = names.iterator();
while(iterator.hasNext()) {
String name = iterator.next();
if(name.equals("bob")) {
iterator.remove();
}
}
但是,要查找重复项,我会完全使用不同的方法。我会使用Set
集合,而不是使用嵌套循环。集合不能包含重复项,如果您尝试向集合添加副本,add()
方法将返回false。
如果迭代列表,将每个项目添加到集合中并检查add()
方法是否返回false,您将知道何时复制。您可以将其从列表中删除,也可以将该集合保留在最后,并将其用于您的名称集合,而不会重复。
这里有一个问题,答案说明了这种方法。你将以这种方式消耗更多的空间(你将在内存中同时拥有一个列表和一个集合),但是每次你必须检查重复时,不会在列表上进行迭代,从而节省了大量的时间。根据列表的大小,这可能是理想的,也可能不是理想的。
编辑:实际上,您可以将您的名称列表和批量添加到集合中,并且重复项将被删除:
Set<String> namesNoDuplicates = new HashSet<String>();
namesNoDuplicates.addAll(names);