5

I have an array (moves) of arrays. I want to iterate through my moves array and set a condition for each element. The condition is, if either number in the element is negative, then I want to remove that element from the moves array. The loop does not remove my items correctly. BUT if I run it through the exact same loop twice, then it WILL remove the last element. This makes no sense to me. Using Python 3.6

moves = [[3,-1],[4,-1],[5,-1]]
for move in moves:
    if move[0] < 0 or move[1] < 0:
        moves.remove(move)

If you run this code, moves ends with a result of [[4,-1]] But if you run this result through the exact same for loop again, the result is []

I also tried doing this with many more elements and it's just not grabbing certain elements for some reason. Is this a bug with .remove()? This is what I tried...(In this I tried detecting nonnegative number to see if that was part of the issue, it wasn't)

moves = [[3,1],[4,1],[5,1],[3,1],[4,1],[5,1],[3,1],[4,1],[5,1]]
    for move in moves:
        if move[0] < 2 or move [1] < 2:
            moves.remove(move)

The result of the above code is

moves = [[4, 1], [3, 1], [4, 1], [5, 1]]

Any ideas???

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
Alec Mather
  • 742
  • 5
  • 20
  • 2
    Do not iterate and modify the list you iterate at the same time. – Patrick Artner Nov 11 '18 at 18:46
  • So then how do I filter the list based on a condition? – Alec Mather Nov 11 '18 at 18:48
  • In your 2nd example nothing would beleft as all elements have onne inner element < 2 .. what are you trying to do? – Patrick Artner Nov 11 '18 at 18:51
  • Yoiur 1st example would also not have anything left - as all elements contain 1 eleemnt less then 0 – Patrick Artner Nov 11 '18 at 18:52
  • @PatrickArtner yes I'm aware that that is what is SUPPOSED to happen, but as you can see from the output, that isn't what's happening. That's what the question is about :) – Alec Mather Nov 11 '18 at 19:08
  • Usually its better to have a postitive/negative example - where _some_ elements are filtered and _some_ elements pass through the filter - as example. Thats better so nobody suggests `def fn(iterable): return []` as solution ;o) – Patrick Artner Nov 11 '18 at 19:10

2 Answers2

5

You can iterate through a copy of a list. This can be done by adding [:] in your for loop list moves[:].

Input

moves = [[3,-1],[4,-1],[5,-11], [2,-2]]
for move in moves[:]:
    if (move[0] < 0) or (move[1] < 0):
        moves.remove(move)

print(moves)

Output

[]
Naveen
  • 1,190
  • 7
  • 20
2

Dont iterate and modify at the same time.

You can use a list comp or filter() to get a list that fits your needs:

moves = [[3,1],[4,-1],[5,1],[3,-1],[4,1],[5,-1],[3,1],[-4,1],[-5,1]]

# keep all values of which all inner values are > 0
f = [x for x in moves if all(e>0 for e in x)]

# same with filter()
k = list(filter(lambda x:all(e>0 for e in x), moves))

# as normal loop
keep = []
for n in moves:
    if n[0]>0 and n[1]>0:
        keep.append(n)

print(keep)

print(f) # f == k == keep  

Output:

[[3, 1], [5, 1], [4, 1], [3, 1]]

Doku for filter() and all() can be found at the overview on built in functions

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69