【问题标题】:Removing duplicates from arraylist从arraylist中删除重复项
【发布时间】:2015-12-12 10:19:04
【问题描述】:
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个或更多是不可能的。

【问题讨论】:

  • 不确定这是否真的是问题所在,但您的内部 for 循环缺少大括号。
  • 我认为只要去掉name.remove(i);这一行就可以了。您不需要删除重复的两次。
  • 我正在尝试删除重复的对。
  • 那么您需要一种完全不同的方法。如果列表包含三个相同的项目,答案应该是什么?
  • 抱歉这个令人困惑的问题。 arraylist 仅携带重复的对或唯一元素。没有 3 个或更多项目是相同的。

标签: java arraylist


【解决方案1】:

我认为这行得通。您有 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;
        }
}

【讨论】:

    【解决方案2】:

    当您从列表中删除项目时,索引会发生变化,这不仅会导致 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来删除所有重复的项目。

    现在,这依赖于对象的 hashcodeequals 实现来工作

    【讨论】:

      【解决方案3】:

      我不会从您正在迭代的列表中删除项目。可以调整索引,但会导致代码难以阅读。

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

      这里有一个问题的答案说明了这种方法。这样你会消耗更多的空间(你将在内存中同时拥有一个列表和一个集合),但是你将节省大量时间,因为每次你必须检查重复时都不需要遍历列表。根据您列表的大小,这可能是理想的,也可能不是理想的。

      Identify duplicates in a List

      编辑:实际上,您可以只获取您的姓名列表并将它们批量添加到集合中,然后重复项将被删除:

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

      【讨论】:

        猜你喜欢
        • 2018-05-29
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-04
        • 2021-12-24
        相关资源
        最近更新 更多