在迭代期间向集合添加元素

gri*_*ton 76 java iterator

是否可以在迭代时向元素添加元素?

更具体地说,我想迭代一个集合,如果一个元素满足某个条件,我想在集合中添加一些其他元素,并确保迭代这些添加的元素.(我意识到这可能导致一个无终止的循环,但我很确定它不会在我的情况下.)

Sun 的Java教程表明这是不可能的:"请注意,这Iterator.remove是在迭代期间修改集合的唯一安全方法;如果在迭代进行过程中以任何其他方式修改基础集合,则行为未指定."

所以如果我不能用迭代器做我想做的事,你建议我做什么?

Avi*_*Avi 60

如何使用您想要迭代的元素构建一个Queue; 当您想要添加元素时,将它们排入队列的末尾,并继续删除元素,直到队列为空.这是广度优先搜索通常的工作方式.

  • `ListIterator iter = list.listIterator()`有`add()`和`remove()`方法,所以你可以在迭代过程中添加和删除元素 (30认同)
  • @soulmachine你确定吗?如果我尝试这样做,我会得到一个ConcurrentModificationException. (4认同)
  • 如果它适合OP编码的模型,这是一种很好的方法.这样你就不会使用迭代器 - 只需一个while循环.虽然队列中有元素,但处理第一个元素.但是,您也可以使用List执行此操作. (2认同)

coo*_*ird 46

这里有两个问题:

第一个问题是,CollectionIterator返回之后添加.如上所述,在Collection修改底层证书时没有定义的行为,如以下文档中所述Iterator.remove:

...如果在迭代正在进行中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为.

第二个问题是,即使Iterator可以获得,然后返回到相同的元素Iterator,也不能保证迭代的顺序,如Collection.iterator方法文档中所述:

...没有关于元素返回顺序的保证(除非此集合是某个提供保证的类的实例).

例如,假设我们有列表[1, 2, 3, 4].

比方说,5当加Iterator3,不知何故,我们得到了一个Iterator能够恢复从迭代4.但是,没有任何保证人5会追随4.迭代顺序可能是[5, 1, 2, 3, 4]- 然后迭代器仍然会错过元素5.

由于无法保证行为,因此不能假设事情会以某种方式发生.

一种替代方法是可以将Collection新创建的元素添加到其中,然后迭代这些元素:

Collection<String> list = Arrays.asList(new String[]{"Hello", "World!"});
Collection<String> additionalList = new ArrayList<String>();

for (String s : list) {
    // Found a need to add a new element to iterate over,
    // so add it to another list that will be iterated later:
    additionalList.add(s);
}

for (String s : additionalList) {
    // Iterate over the elements that needs to be iterated over:
    System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)

编辑

详细说明Avi的答案,可以将我们想要迭代的元素排队到队列中,并在队列中包含元素时删除元素.除了原始元素之外,这将允许对新元素进行"迭代".

让我们来看看它是如何工作的.

从概念上讲,如果队列中包含以下元素:

[1, 2, 3, 4]

并且,当我们删除时1,我们决定添加42,队列将如下所示:

[2, 3, 4, 42]

由于队列是FIFO(先进先出)数据结构,因此这种排序是典型的.(如Queue接口文档中所述,这不是a的必要条件Queue.PriorityQueue以其自然顺序对元素进行排序,因此不是FIFO.)

以下是使用a LinkedList(a 是a Queue)的示例,以便遍历所有元素以及在dequeing期间添加的其他元素.与上面的示例类似,删除42元素时添加元素2:

Queue<Integer> queue = new LinkedList<Integer>();
queue.add(1);
queue.add(2);
queue.add(3);
queue.add(4);

while (!queue.isEmpty()) {
    Integer i = queue.remove();
    if (i == 2)
        queue.add(42);

    System.out.println(i);
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

1
2
3
4
42
Run Code Online (Sandbox Code Playgroud)

如所希望的那样,42我们击中时添加的元素2出现了.


McD*_*ell 8

您可能还想查看一些更专业的类型,如ListIterator,NavigableSet和(如果您对地图感兴趣)NavigableMap.


Pat*_*aDJ 5

其实还是比较容易的。只考虑最佳方式。我相信最佳方法是:

for (int i=0; i<list.size(); i++) {
   Level obj = list.get(i);

   //Here execute yr code that may add / or may not add new element(s)
   //...

   i=list.indexOf(obj);
}
Run Code Online (Sandbox Code Playgroud)

以下示例在最合乎逻辑的情况下完美运行 - 当您不需要在迭代元素之前迭代添加的新元素时。关于迭代元素之后添加的元素 - 您可能也不希望迭代它们。在这种情况下,您应该简单地添加/或扩展带有标志的 yr 对象,该标志将标记它们而不是迭代它们。


Ste*_*veR 5

使用ListIterator方法如下:

List<String> l = new ArrayList<>();
l.add("Foo");
ListIterator<String> iter = l.listIterator(l.size());
while(iter.hasPrevious()){
    String prev=iter.previous();
    if(true /*You condition here*/){
        iter.add("Bah");
        iter.add("Etc");
    }
}
Run Code Online (Sandbox Code Playgroud)

关键是以相反的顺序迭代 - 然后添加的元素出现在下一次迭代中。