【问题标题】:Iterating through a list and allowing it to have an item removed at the same time (NOT ITERATOR)遍历一个列表并允许它同时删除一个项目(NOT ITERATOR)
【发布时间】:2012-08-20 11:35:00
【问题描述】:

注意:我不知道 doSomething 是否会删除该元素。这是我的数据结构需要处理的例外情况。

我的问题很简单:

int size = list.size();
for(int i = 0; i < size; i++) {
   MyObj mo = list.get(i);
   mo.doSomething();
}

现在如果 doSomething() 从列表中删除 mo,我最终会得到一个 ArrayIndexOutOfBounds,因为列表现在已经缩小了。

我应该使用什么数据结构来允许迭代并可能删除?我不能在这里使用迭代器,换句话说,我不能让 doSomething 返回一个布尔值并调用 iterator.remove()。数据结构必须以某种方式处理这种情况并继续迭代仍然存在的其余元素。

编辑:我不知道 doSomething 是否会删除该元素。这是我的数据结构需要处理的例外情况。

第二部分 => Making a smart listeners notifier to avoid code duplication everywhere

【问题讨论】:

  • 你知道doSomething()是否真的删除了mo吗?如果是这样,请稍后致电--i,您会没事的。
  • @TomaszNurkiewicz 这就是问题所在,Tomasz,我不知道,所以你的解决方案不起作用。 :(

标签: java algorithm list data-structures collections


【解决方案1】:

例如,您可以使用ArrayList,只要您在删除某些内容时更新索引和大小。

List<MyObj> list = new ArrayList<MyObj>();
int size = list.size();
for(int i = 0; i < size; i++) {
    MyObj mo = list.get(i);
    mo.doSomething();
    if (size > list.size()) {
        size = list.size();
        i--;
    }
}

这仅在删除的项目是最后检查的项目时才有效。对于列表的其他更改,您将必须有更复杂的逻辑。

【讨论】:

  • 这不起作用,因为我不知道该元素是否会被删除。在问题中查看我的编辑。
  • @chrisapotek:好的,更改以检查是否删除了某些内容。
  • 嗯。只要删除的元素是当前正在迭代的元素,您确定这有效吗?
  • @chrisapotek:在这种情况下,我敢肯定,是的。
  • @chrisapotek:当你移除一个对象时,后面的对象会向下移动,所以你需要再次检查相同的索引。
【解决方案2】:

我应该使用什么数据结构来允许可以删除的迭代?

最简单的选择是获取列表的副本并迭代 that

List<MyObj> copy = new ArrayList<MyObj>(list);
for (MyObj mo : copy) {
    mo.doSomething();
}

现在无论是否有任何东西从原始列表中删除一个想法都没有关系 - 这不会改变列表的副本。

另一种选择是使用CopyOnWriteArrayList。然后,您可以随意迭代和删除或添加项目:

“快照”样式的迭代器方法使用对创建迭代器时数组状态的引用。这个数组在迭代器的生命周期内永远不会改变,所以干扰是不可能的,并且迭代器保证不会抛出 ConcurrentModificationException。自创建迭代器以来,迭代器不会反映对列表的添加、删除或更改。

【讨论】:

  • 感谢 Jon,但每次在迭代前复制成本太高。我猜@Keppil 的建议效果更好。
  • @chrisapotek:查看我的编辑 - CopyOnWriteArrayList 可能更合适。我个人会更满意这种解决方案,该解决方案仅在允许的 only 更改是删除当前元素时才有效。
  • 感谢 CopyOnWriteArrayList 课程建议。
【解决方案3】:

我认为你应该改变你doSomething()。如果mo.doSomething() 可以从l 中删除mo,则您的mo 必须知道您的l

您可以像这样更改代码:

在您的 MyObj 中创建一个有效标志。仅在有效时才收听。

while(list.hasNext()) {
   MyObj mo = list.next()
   if(mo.isValid()){
       mo.doSomething();
   } else {
       list.remove();
   }
}

【讨论】:

  • 它确实知道... mo 将自己作为侦听器从列表中删除,麻烦出现了... 为什么您觉得这听起来很奇怪?
  • 我知道你写了“不是迭代器”,但我认为这是因为你把自己从列表中删除了。
  • 这不起作用。我只知道执行 doSomething 后 mo 是否有效...
  • 这会起作用,但不会在第一次迭代中起作用。在您第二次遍历列表时,您将从列表中删除 mo。这将导致一个包含无效 mo 的列表。但是你写的性能是至关重要的。如果列表中没有那么多项目,它可能会起作用。
猜你喜欢
  • 2012-06-13
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-02
相关资源
最近更新 更多