简体   繁体   中英

Remove a specific index from a list while iterating in Python

I learn how to remove items from a list while iterating from here by:

somelist = [x for x in somelist if determine(x)]

Further, how do I remove a specific index from a list while iterating? For instance,

lists = list() # a list of lists

for idx, line in enumerate(lists):
    if idx > 0:
        cur_val = line[0] # value of current line
        prev_val = lists[idx-1][0] # value of previous line

        if prev_val == cur_val :
            del lists[idex-1] # IndexError: list index out of range

Basically your attempt is not supported according to any documentation. In general you should not modify a container while iterating unless the documentation explicitly says that you can. It doesn't help if it "seems to work" since you then just exploiting some behavior in the version of the implementation you're using, but that behavior can change without prior notice (breaking your program).

What you need to do is making the modification separate from the iteration. Using list comprehension is one way to achieve this, but basically you're doing the same thing.

There's a few variants, either you make a copy of the data and iterate through that and modify the original. Or you make a copy before iterating the original and modify the copy and then updates the original. There's also the variant where you build the copy during iteration and then update the original.

In addition your example is flawed because you don't take into account that modification affects the proper index in the modified list . For example if you have the list [1, 1, 2, 2, 3, 3] , then when you've removed the duplicates 1 s and 2 s and detect duplicate 3 s you have the list [1, 2, 3, 3] , but when you find the duplicate 3 s you find these at index 4 and 5 , but after the deletion they are at index 2 and 3 instead.

lists = list() # a list of lists

cur = 0 # index in the modified list
for idx, line in list(enumerate(lists)): # make a copy of the original
    if idx > 0:
        cur_val = line[0] # value of current line
        prev_val = lists[idx-1][0] # value of previous line

        if prev_val == cur_val:
            del lists[cur-1] # IndexError: list index out of range
        else:
            cur += 1
    else:
        cur += 1

The solution where you modify a copy instead is basically the same, but the solution where you build the copy during iteration is a bit different.

lists = list() # a list of lists

tmp = []
for idx, line in enumerate(lists): # make a copy of the original
    if idx > 0:
        cur_val = line[0] # value of current line
        prev_val = lists[idx-1][0] # value of previous line

        if prev_val != cur_val:
            tmp.append(line)
    else:
        tmp.append( line )

 lists[:] = tmp

The last line is where the origin is updated, otherwise the loop works by appending those elements that are to be kept to tmp (instead of copying all and then remove those that's not to be kept).

您可以使用列表推导产生相同的结果:

somelist = [i for idx, i in enumerate(lists) if i[0] != lists[idx][0]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM