Python: Adding element to list while iterating

前端 未结 11 583
太阳男子
太阳男子 2020-12-02 15:37

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:



        
相关标签:
11条回答
  • 2020-12-02 15:49

    In short: If you'are absolutely sure all new objects fail somecond() check, then your code works fine, it just wastes some time iterating the newly added objects.

    Before giving a proper answer, you have to understand why it considers a bad idea to change list/dict while iterating. When using for statement, Python tries to be clever, and returns a dynamically calculated item each time. Take list as example, python remembers a index, and each time it returns l[index] to you. If you are changing l, the result l[index] can be messy.

    NOTE: Here is a stackoverflow question to demonstrate this.

    The worst case for adding element while iterating is infinite loop, try(or not if you can read a bug) the following in a python REPL:

    import random
    
    l = [0]
    for item in l:
        l.append(random.randint(1, 1000))
        print item
    

    It will print numbers non-stop until memory is used up, or killed by system/user.

    Understand the internal reason, let's discuss the solutions. Here are a few:

    1. make a copy of origin list

    Iterating the origin list, and modify the copied one.

    result = l[:]
    for item in l:
        if somecond(item):
            result.append(Obj())
    

    2. control when the loop ends

    Instead of handling control to python, you decides how to iterate the list:

    length = len(l)
    for index in range(length):
        if somecond(l[index]):
            l.append(Obj())
    

    Before iterating, calculate the list length, and only loop length times.

    3. store added objects in a new list

    Instead of modifying the origin list, store new object in a new list and concatenate them afterward.

    added = [Obj() for item in l if somecond(item)]
    l.extend(added)
    
    0 讨论(0)
  • 2020-12-02 15:52

    well, according to 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.

    0 讨论(0)
  • 2020-12-02 15:54

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

    for i in xrange(len(myarr)):
        if somecond(a[i]):
            myarr.append(newObj())
    
    0 讨论(0)
  • 2020-12-02 15:55

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

    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.

    0 讨论(0)
  • 2020-12-02 16:04

    Alternate solution :

    reduce(lambda x,newObj : x +[newObj] if somecond else x,myarr,myarr)
    
    0 讨论(0)
提交回复
热议问题