【问题标题】:Arraylist looping malfunctionArraylist 循环故障
【发布时间】:2015-08-12 01:43:20
【问题描述】:

我有一个 MainList 有 61 个元素和一个 subList 有 9 个元素。 在subList 的9 个元素中,有8 个在MainList

我的目标只是删除两个列表中存在的那些对象。

for(int i = 0; i < subList.size();i++){
    for(int j = 0; j < mainList.size();j++){
        if(subList.get(i).equals(mainList.get(j))){
            mainList.remove(j);
            subList.remove(i);

            break;
        }
    }
} 

我面临的问题是,在 forloop 之后,subList 仍然保留 5 个元素,这意味着 forloop 只能找到 4 个相似的对象。

后来我又写了一个forloop来调试情况如下:

for(int i = 0; i < subList.size();i++){
    for(int j = 0; j < mainList.size();j++){
    if(subList.get(i).equals(mainList.get(j))){
            System.out.println("something");
        }
   }
}

我可以看到 4 次“某物”。我想知道为什么第一个 forloop 没有找到所有相似的对象?

【问题讨论】:

  • 不要使用索引循环并更改循环内的集合,这很可能会导致错误。请改用迭代器。

标签: java for-loop arraylist


【解决方案1】:

放弃循环并使用 Collection.removeAll

删除该集合的所有元素,这些元素也包含在 指定的集合(可选操作)。在这个电话之后 返回,此集合将不包含与 指定的集合。

由于您想从两个列表中删除重复项,您需要先复制其中一个列表。

List<?> sublistCopy = new ArrayList(sublist);

subList.removeAll(mainList);
mainList.removeAll(sublistCopy);

【讨论】:

    【解决方案2】:

    为什么不使用Collection.removeAll() 方法:

    mainList.removeAll( subList );
    

    remove()'来自List会更改索引。建议使用Iterator 遍历并从集合中移除:

    for ( Iterator<...> iterator = mainList.iterator() ; iterator.hasNext() ; ) {
        Object o = iterator.next();
        if (subList.contains( o )  ) { iterator.remove(); }
    }
    

    干杯,

    【讨论】:

    • 我认为mainList.removeAll( subList ) 只会从 mainList 中删除公共对象,而不是从 subList 中删除
    • 确实如此。目前尚不清楚 OP 是否只希望删除主要元素或对称情况。无论如何,扩展到您描述的情况是微不足道的。关键是 OP 应该使用内置方法。
    【解决方案3】:

    您不应该同时使用索引修改列表。您可以使用 while 循环和 iterator

    根据文档:

    迭代器允许调用者在迭代期间以定义明确的语义从底层集合中删除元素。

    【讨论】:

      【解决方案4】:

      当你从 ArrayList 中删除一个元素时,它后面的元素的索引会减一,因此你应该减少循环的索引来解决这个问题。

      例如,subList.remove(3); 会将索引 4 处的元素移动到索引 3,因此为了让您的循环不跳过该元素,您应该减少循环的索引。

      for(int i = 0; i < subList.size();i++){
          for(int j = 0; j < mainList.size();j++){
              if(subList.get(i).equals(mainList.get(j))){
                  mainList.remove(j);
                  subList.remove(i);
                  i--;
                  j--; // actually j-- may not be needed, since you break
                       // from the inner loop and start a new inner loop
                  break;
              }
          }
      } 
      

      【讨论】:

      • 我认为一个更优雅的选择是向后退,从 sublist.size() 到 0。这样你就不必“手动”减少索引
      • @Pablo 我认为使用迭代器的 remove 方法会更加优雅。那么你就完全不用担心索引了。
      【解决方案5】:

      确保两个元素相等(检查列表中是否包含一些空格)。

      for(int i=0;i<subList.size();i++){
          if(mainList.contains(subList.get(i)){
                mainList.remove(subList.get(i));  //remove the element from mainList.
                subList.remove(i);   //removes the element from subList.
      
          } 
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-03
        • 1970-01-01
        • 1970-01-01
        • 2018-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-20
        相关资源
        最近更新 更多