2

My code looks like this:

def nue(li):
    for i in li:
        li.remove(i)
    print(li)

li = [1, 2, 3]

nue(li)

However, running this results in:

>>> [2]

More generally, how do I remove the i-th position on a list while iterating over the list (for reasons it failed some test in a nested loop or something like that)?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • 5
    Don't. Build a new list. – user2357112 Jan 18 '18 at 17:36
  • If you want to empty the list, why not just use `li=[]` ? – rnso Jan 18 '18 at 17:38
  • 4
    Removing items from a list that you're iterating over is like sawing off a tree branch that you're sitting on. If you're not very careful Bad Things happen. It's generally simpler, and faster, to just build a new list. – PM 2Ring Jan 18 '18 at 17:39
  • @rnso thats like a nuking a house to get rid of a spider – Max Jan 18 '18 at 17:39
  • @rnso Because I want this as a part of a bigger loop, which tests the elements of the list one-by-one and deletes them as needed. – RichardTheCoder Jan 18 '18 at 17:40
  • If you need to keep the original list object you can use a slice assignment, eg `li[:] = [u for u in li if u != 2]` – PM 2Ring Jan 18 '18 at 17:40
  • @user2357112 Right, thank you. Also, why does this result in a: [2] ??? That seems even more perplexing. – RichardTheCoder Jan 18 '18 at 17:41
  • @RichardTheCoder https://eval.in/937673 – splash58 Jan 18 '18 at 17:41
  • Even when you aren't using it in a loop, the `list.remove` method should be used sparingly. It's relatively slow because it has to perform a linear scan over the list looking for the item to remove, and then once it's removed the item it has to move all of the subsequent items down to fill the gap. Sure, it does those things at C speed, but it's still better to avoid doing that when you can. – PM 2Ring Jan 18 '18 at 17:43
  • 1
    Try your remove loop on `[1, 2, 3, 4, 5, 6, 7]`. You should be able to see the pattern. – PM 2Ring Jan 18 '18 at 17:45

4 Answers4

1

you can do like this

def nue(li):
    for i in li[:]:
        li.remove(i)
    print(li)

li = [1, 2, 3]

nue(li)

li[:] will clone original li

Haseeb A
  • 5,356
  • 1
  • 30
  • 34
0

Try list comprehension:

def remi(slist, i):    # remi means REMove I
    return [slist[j] 
            for j in range(len(slist))
            if j != i]

print(remi ([1,2,3,4], 2))

Output:

[1, 2, 4]
rnso
  • 23,686
  • 25
  • 112
  • 234
0

Why not just use a list comprehension instead of removing items from an existing list?

old_list = [1,2,3,4,5]
li = [1,2,3]
new_list = [i for i in old_list if i not in li]

If you don't want to use a list comprehension you can try the filter function

old_list = [1,2,3,4,5]
li = [1,2,3]
new_list = list(filter(lambda x: x not in li, old_list))
APorter1031
  • 2,107
  • 6
  • 17
  • 38
0

You might want to consider going over the array in reverse. The following code demonstrates three functions that do the same thing. All are called prune and are interchangeable. By looking at an array in reverse order, you avoid changing the index of values you will examine in the future.

#! /usr/bin/env python3
def main():
    array = list(range(20))
    print(array)
    prune(array, lambda value: value % 3)
    print(array)


def prune(array, del_condition):
    for index, value in reversed(tuple(enumerate(array))):
        if del_condition(value):
            del array[index]


def prune(array, del_condition):
    for index in range(len(array) - 1, -1, -1):
        value = array[index]
        if del_condition(value):
            del array[index]


def prune(array, del_condition):
    for index in reversed(range(len(array))):
        if del_condition(array[index]):
            del array[index]


if __name__ == '__main__':
    main()
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117