Python:在迭代时将元素添加到列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3752618/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:33:47  来源:igfitidea点击:

Python: Adding element to list while iterating

pythoniteration

提问by WesDec

I know that it is not allowed to remove elements while iterating a list, but is it allowed to add elements to a python list while iterating. Here is an example:

我知道在迭代列表时不允许删除元素,但允许在迭代时将元素添加到 python 列表中。下面是一个例子:

    for a in myarr:
      if somecond(a):
          myarr.append(newObj())

I have tried this in my code and it seems to work fine, however I don't know if it's because I am just lucky and that it will break at some point in the future?

我已经在我的代码中尝试过这个,它似乎工作正常,但是我不知道是不是因为我很幸运,它会在未来的某个时候崩溃?

EDIT: I prefer not to copy the list since "myarr" is huge, and therefore it would be too slow. Also I need to check the appended objects with "somecond()".

编辑:我不想复制列表,因为“myarr”很大,因此它太慢了。我还需要用“somecond()”检查附加的对象。

EDIT: At some point "somecond(a)" will be false, so there can not be an infinite loop.

编辑:在某些时候“somecond(a)”会是假的,所以不可能有无限循环。

EDIT: Someone asked about the "somecond()" function. Each object in myarr has a size, and each time "somecond(a)" is true and a new object is appended to the list, the new object will have a size smaller than a. "somecond()" has an epsilon for how small objects can be and if they are too small it will return "false"

编辑:有人询问了“somecond()”函数。myarr 中的每个对象都有一个大小,每次“somecond(a)”为真并且一个新对象被添加到列表中时,新对象的大小将小于 a。"somecond()" 有一个 epsilon,表示对象可以有多小,如果它们太小,它将返回 "false"

采纳答案by wheaties

You could use the islicefrom itertools to create an iterator over a smaller portion of the list. Then you can append entries to the list without impacting the items you're iterating over:

您可以使用islicefrom itertools 在列表的较小部分上创建迭代器。然后,您可以将条目附加到列表中,而不会影响您正在迭代的项目:

islice( myarr, 0, len(myarr)-1 )

Even better, you don't even have to iterate over all the elements. You can increment a step size.

更好的是,您甚至不必遍历所有元素。您可以增加步长。

回答by shahjapan

make copy of your original list, iterate over it, see the modified code below

复制您的原始列表,对其进行迭代,请参阅下面的修改后的代码

for a in myarr[:]:
      if somecond(a):
          myarr.append(newObj())

回答by Rohan Monga

well, according to http://docs.python.org/tutorial/controlflow.html

好吧,根据http://docs.python.org/tutorial/controlflow.html

It is not safe to modify the sequence being iterated over in the loop (this can only happen for mutable sequence types, such as lists). If you need to modify the list you are iterating over (for example, to duplicate selected items) you must iterate over a copy.

修改循环中迭代的序列是不安全的(这只会发生在可变序列类型,例如列表)。如果您需要修改您正在迭代的列表(例如,复制选定的项目),您必须迭代一个副本。

回答by eumiro

Access your list elements directly by i. Then you can append to your list:

通过 i 直接访问您的列表元素。然后你可以附加到你的列表中:

for i in xrange(len(myarr)):
    if somecond(a[i]):
        myarr.append(newObj())

回答by S.Lott

You can do this.

你可以这样做。

bonus_rows = []
for a in myarr:
  if somecond(a):
      bonus_rows.append(newObj())
myarr.extend( bonus_rows )

回答by Mike DeSimone

Expanding S.Lott's answer so that new items are processed as well:

扩展 S.Lott 的答案,以便处理新项目:

todo = myarr
done = []
while todo:
    added = []
    for a in todo:
        if somecond(a):
            added.append(newObj())
    done.extend(todo)
    todo = added

The final list is in done.

最终名单在done.

回答by Johnny

Why don't you just do it the idiomatic C way? This ought to be bullet-proof, but it won't be fast. I'm pretty sure indexing into a list in Python walks the linked list, so this is a "Shlemiel the Painter" algorithm. But I tend not to worry about optimization until it becomes clear that a particular section of code is really a problem. First make it work; then worry about making it fast, if necessary.

你为什么不按照惯用的 C 方式来做呢?这应该是防弹的,但不会很快。我很确定在 Python 中索引到一个列表会遍历链表,所以这是一个“Shlemiel the Painter”算法。但我倾向于不担心优化,直到很明显特定的代码部分确实是一个问题。首先让它工作;如果有必要,那么担心让它变快。

If you want to iterate over all the elements:

如果要遍历所有元素:

i = 0  
while i < len(some_list):  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1  

If you only want to iterate over the elements that were originally in the list:

如果您只想迭代列表中最初的元素:

i = 0  
original_len = len(some_list)  
while i < original_len:  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1

回答by RemcoGerlich

I had a similar problem today. I had a list of items that needed checking; if the objects passed the check, they were added to a result list. If they didn'tpass, I changed them a bit and if they might still work (size > 0 after the change), I'd add them on to the back of the list for rechecking.

我今天遇到了类似的问题。我有一份需要检查的物品清单;如果对象通过检查,它们将被添加到结果列表中。如果他们没有通过,我对它们进行了一些更改,如果它们仍然可以工作(更改后大小 > 0),我会将它们添加到列表的后面进行重新检查。

I went for a solution like

我去找了一个解决方案

items = [...what I want to check...]
result = []
while items:
    recheck_items = []
    for item in items:
        if check(item):
            result.append(item)
        else:
            item = change(item)  # Note that this always lowers the integer size(),
                                 # so no danger of an infinite loop
            if item.size() > 0:
                recheck_items.append(item)
    items = recheck_items  # Let the loop restart with these, if any

My list is effectively a queue, should probably have used some sort of queue. But my lists are small (like 10 items) and this works too.

我的列表实际上是一个队列,可能应该使用某种队列。但是我的列表很小(比如 10 个项目),这也有效。

回答by HelloGoodbye

You can use an index and a while loop instead of a for loop if you want the loop to also loop over the elements that is added to the list during the loop:

如果您希望循环也循环遍历在循环期间添加到列表的元素,则可以使用索引和 while 循环而不是 for 循环:

i = 0
while i < len(myarr):
    a = myarr[i];
    i = i + 1;
    if somecond(a):
        myarr.append(newObj())

回答by Akshay Hazari

Alternate solution :

替代解决方案:

reduce(lambda x,newObj : x +[newObj] if somecond else x,myarr,myarr)