java - 在 for 循环中使用迭代器从 ArrayList 中删除元素

标签 java arraylist iterator

我有一个包含版本号作为字段的对象的 ArrayList。我想对该 ArrayList 做一些工作,但我只想要该对象的最新版本。我在考虑这样编码:

ArrayList<ObjectVO> ObjectList = getObjectList();
for(ObjectVO myVO : ObjectList) {
  Iterator<ObjectVO> iter = ObjectList.iterator();

  while(iter.hasNext()) {
     ObjectVO checkVO = iter.next();
     if(myVO.getID().equals(checkVO.getID()) {
         //they are the same object ID.  Check the version number, remove it lower
         if(myVO.getVersion() > checkVO.getVersion()) {
              iter.remove();
         }
      }
   }
 }

这有效吗?我不知道我们最初处于 for 循环中的事实是否会在运行时破坏 ArrayList 的可变性。

最佳答案

不,这行不通。 iter.remove() 将导致 out for 循环失败并返回 ConcurrentModificationException

您可以使用带索引的 for 循环和 BitSet 来跟踪要删除的内容,而不是这样做:

BitSet toRemove = new BitSet();
for (int m = 0; m < ObjectList.size(); ++m) {
  if (toRemove.get(m)) continue;
  ObjectVO myVO = ObjectList.get(m);

  for (int c = 0; c < ObjectList.size(); ++c) {
    if (toRemove.get(c)) continue;
    ObjectVO checkVO = ObjectList.get(c);

    if(myVO.getID().equals(checkVO.getID()) {
      //they are the same object ID.  Check the version number, remove it lower
      if(myVO.getVersion() > checkVO.getVersion()) {
          toRemove.set(c);
      }
    }
  }
}

这基本上是您的代码,但它还没有执行删除操作。然后您可以扫过列表并删除它们:

int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
  if (!toRemove.get(src)) {
    ObjectList.set(dst++, ObjectList.get(src));
  }
}
ObjectList.subList(dst, ObjectList.size()).clear();

像这样使用 BitSet 的要点是,如果您要从末尾以外的任何地方删除,从 ArrayList 中删除是低效的,因为它需要所有的您删除的元素“右侧”的元素将被洗牌一个位置。带有 set/get 和 clear 的循环允许您只移动每个保留的元素一次。


不过,如果您按具有相同 ID 的事物对列表元素进行分组,您可以比二次循环做得更好:那么您就不需要继续检查整个列表:

BitSet toKeep = new BitSet();
IntStream.range(0, ObjectList.size())
    .mapToObj(a -> a)
    .collect(
        groupingBy(a -> ObjectList.get(a).getID(),
                   maxBy(comparingInt(a -> ObjectList.get(a).getVersion()))))
    .values()
    .forEach(a -> toKeep.set(a));

int dst = 0;
for (int src = 0; src < ObjectList.size(); ++src) {
  if (toKeep.get(src)) {
    ObjectList.set(dst++, ObjectList.get(src));
  }
}
ObjectList.subList(dst, ObjectList.size()).clear();

关于java - 在 for 循环中使用迭代器从 ArrayList 中删除元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56694171/

相关文章:

c# - 询问 - 如何将多个 List<T> 添加到具有特定名称的 List<T>

java - 使用一个迭代器删除多个列表的条目

c++ - 使用迭代器将 int 值赋给 vector

java - 当两个不同的 wicket 应用程序共享通用功能时,如何重用代码

java - Java中的顺序视频播放(剪切列表)..可以做到吗?

java - 如何使用 JavaFX 定期显示一幅图像

Java:难道不能使用迭代器来迭代对象的HashMap并改变对象的属性吗?

java - 使用java和opencv对灰度图像进行图像融合给出了奇怪的结果

java - if 语句和 for 循环中 ArrayList 的问题

java - 检索数据重复错误