繁体   English   中英

从arraylist中删除重复项

[英]Removing duplicates from 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:索引:1,大小:1

请注意,我正在尝试删除重复的对。 arraylist中只能有两个相同的元素。 不能超过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;
        }
}

从列表中删除项目时,索引会发生变化,这不仅会导致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 ,然后在内部循环完成之后将其传递到原始ListremoveAll方法

内部循环从当前/外部索引(加1)开始,因为我们已经处理了它之前的所有值,所以我们不需要继续循环这些项

从理论上讲,您可以简单地继续向discard List添加元素,并在末尾执行单个removeAll

更新...

因此,我想知道是否可能存在使用Java 8以及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并且equals实现的对象的实现

我不会从您要遍历的列表中删除项目。 可以调整索引,但这会使难以阅读的代码成为可能。

相反,您可以使用Iterator ,它将为您处理索引调整。

这是一个简单的示例来说明这个概念(我在某种程度上简化了您的问题,在这种情况下,我不检查重复项,只是“ 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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM