tags:

views:

156

answers:

4

I'm trying to remove some items of a dict based on their key, here is my code:

d1 = {'a': 1, 'b': 2}
d2 = {'a': 1}

l = [d1, d2, d1, d2, d1, d2]

for i in range(len(l)):
    if l[i].has_key('b'):
        del l[i]['b']

print l

The output will be:

[{'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}, {'a': 1}]

Is there a better way to do it?

+16  A: 
d1 = {'a': 1, 'b': 2}
d2 = {'a': 1}
l = [d1, d2, d1, d2, d1, d2]
for d in l:
    d.pop('b',None)
print l
Danra
Alex Martelli
I was worried about the use of 'pop', but it makes sense because of the double indexing, thanks!
igorgue
+3  A: 

A slight simplification:

   for d in l:
      if d.has_key('b'):
         del d['b']

Some people might also do

   for d in l:
      try:
         del d['b']
      except KeyError:
         pass

Catching exceptions like this is not considered as expensive in Python as in other languages.

Kathy Van Stone
+2  A: 

I like your way of doing it (except that you use a loop variable, but others pointed that out already), it's excplicit and easy to understand. If you want something that minimizes typing then this works:

[x.pop('b', None) for x in l]

Note though that only one 'b' will be deleted, because your list l references the dictionaries. So run your code above, and then print out d1, and you'll notice that in fact you deleted the b-key from d1 as well.

To avoid this you need to copy the dictionaries:

d1 = {'a': 1, 'b': 2}
d2 = {'a': 1}

l = [d1.copy(), d2.copy(), d1.copy(), d2.copy(), d1.copy(), d2.copy()]
[b.pop('b', None) for b in l]

d1 will now retain the b key.

Lennart Regebro
-1 for using a list comprehension for their side effects. +1 for the warning about the copy of dicts. Total score: 0
nosklo
Well, I *did* say I didn't like it but that you could. :)
Lennart Regebro
A: 

d1 = {'a': 1, 'b': 2} d2 = {'a': 1}

l = [d1, d2, d1, d2, d1, d2]

for i in range(len(l)): if l[i].has_key('b'): del l[i]['b']

print l

Here is little review of your code:

  1. iterating on list is not done like in C. If you don't need reference the list index it's better to use for item in l and then replace l[i] by item.
  2. for key existence test you can just write if 'b' in l[i]

So your code becomes:

for item in l:
    if 'b' in item:
        del item['b']

One more thing you need to be careful is that on the first iteration that calls del, you will in fact delete all you need as d1 is mutable. You need to think that d1 is a reference and not the value (a bit like a pointer in C).

As Lennart Regebro mentioned to optimize your code you can also use list comprehension.

Nikokrock
Thanks for your feedback, I didn't understand (or remember) that until now
igorgue