从arraylist中删除重复项

时间:2015-09-16 01:25:55

标签: java arraylist

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个或更多。

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即可删除所有重复的项目。

现在,这取决于要运行的对象的removeAllhashcode实现

答案 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,您将知道何时复制。您可以将其从列表中删除,也可以将该集合保留在最后,并将其用于您的名称集合,而不会重复。

这里有一个问题,答案说明了这种方法。你将以这种方式消耗更多的空间(你将在内存中同时拥有一个列表和一个集合),但是每次你必须检查重复时,不会在列表上进行迭代,从而节省了大量的时间。根据列表的大小,这可能是理想的,也可能不是理想的。

Identify duplicates in a List

编辑:实际上,您可以将您的名称列表和批量添加到集合中,并且重复项将被删除:

Set<String> namesNoDuplicates = new HashSet<String>();
namesNoDuplicates.addAll(names);