2

Assuming I have the following list:

array1 = ['A', 'C', 'Desk']

and another array that contains:

array2 = [{'id': 'A', 'name': 'Greg'}, 
{'id': 'Desk', 'name': 'Will'},
{'id': 'E', 'name': 'Craig'},
{'id': 'G', 'name': 'Johnson'}]

What is a good way to remove items from the list? The following does not appear to work

for item in array2:
   if item['id'] in array1:
     array2.remove(item)
2
  • Doesn't remove take an index? Commented Jun 25, 2013 at 18:32
  • @SnakesandCoffee No, remove takes an item and removes the first occurrence of it in a list. Commented Jun 25, 2013 at 18:33

5 Answers 5

7

You could also use a list comprehension for this:

>>> array2 = [{'id': 'A', 'name': 'Greg'},
... {'id': 'Desk', 'name': 'Will'},
... {'id': 'E', 'name': 'Craig'},
... {'id': 'G', 'name': 'Johnson'}]
>>> array1 = ['A', 'C', 'Desk']
>>> filtered = [item for item in array2 if item['id'] not in array1]
>>> filtered
[{'id': 'E', 'name': 'Craig'}, {'id': 'G', 'name': 'Johnson'}]
Sign up to request clarification or add additional context in comments.

Comments

4

You can use filter:

array2 = filter(lambda x: x['id'] not in array1, array2)

5 Comments

As a matter of fact @Paulo Scardine, this should be: array2 = filter(lambda x: x['id'] not in array1, array2) otherwise: AttributeError: 'dict' object has no attribute 'id'
@PeterVaro: Good catch! I guess I'm doing too much javascript these days.
@PeterVaro Filter is not very pythonic. In fact, Guido wants it removed from the language entirely. The pythonic alternative is to use an if statement in a list comprehension.
It's worth noting that filter is a generator in Python 3, so you'd need to wrap this in a list call if you needed an actual list. If you are just going to iterate over it once, then it doesn't matter (unless something else mutates array1 or array2 before you do the iteration).
@Lanaru oh, I always thought that filter is a good tool:) Thanks anyway, although 99% of the time I use list comprehensions with if statements because I forget that there is a filter() function for this.. and it turned out, thanks to you, that it is more pythonic. Sweet.
3

You're modifying a list while iterating over it. Instead iterate over a copy of the list

for item in array2[:]:  # [:] creates a copy
    ...

1 Comment

@Setsuna You are still removing from the original, just iterating over a copy.
2
for item in array2:
   if item['id'] in array1:
     array2.remove(item)

A for loop keeps track of the index during the iterations.

Iteration 1 : Index 0

item is assigned {'id': 'A', 'name': 'Greg'} as it is at index 0.

As 'A' as found in array so you removed this entry from the list.

Due to removal of that item all items to it's right actually shift one place to the left.

So, now {'id': 'Desk', 'name': 'Will'} is at index 0.

Iteration 2 : Index value changed to 1

This time item = {'id': 'E', 'name': 'Craig'} as this is at index 1.

So, as you can see {'id': 'Desk', 'name': 'Will'} was skipped (was never assigned to item) and will not be removed as you expected.

A quick solution is to use a shallow copy of the list for iteration:

for item in array2[:]:  #notice the [:]

Comments

0

Similar to Paulo's answer, but converting to a set first within the filter:

array2[:] = filter(lambda L, S=set(array1): L['id'] not in S, array2)

2 Comments

What's the purpose of [:] here?
@arshajii so that any other names bound to the instance of the list also "have items removed"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.