I have a dictionary of points, say:
>>> points={'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)}
I want to create a new dictionary with all the points whose x and y value is smaller than 5, i.e. points ‘a’, ‘b’ and ‘d’.
According to the the book, each dictionary has the items() function, which returns a list of (key, pair) tuple:
>>> points.items()
[('a', (3, 4)), ('c', (5, 5)), ('b', (1, 2)), ('d', (3, 3))]
So I have written this:
>>> for item in [i for i in points.items() if i[1][0]<5 and i[1][1]<5]:
... points_small[item[0]]=item[1]
...
>>> points_small
{'a': (3, 4), 'b': (1, 2), 'd': (3, 3)}
Is there a more elegant way? I was expecting Python to have some super-awesome dictionary.filter(f) function…
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can use a dict comprehension:
{k: v for k, v in points.items() if v[0] < 5 and v[1] < 5}
And in Python 2, starting from 2.7:
{k: v for k, v in points.iteritems() if v[0] < 5 and v[1] < 5}
Method 2
dict((k, v) for k, v in points.items() if all(x < 5 for x in v))
You could choose to call .iteritems() instead of .items() if you’re in Python 2 and points may have a lot of entries.
all(x < 5 for x in v) may be overkill if you know for sure each point will always be 2D only (in that case you might express the same constraint with an and) but it will work fine;-).
Method 3
points_small = dict(filter(lambda (a,(b,c)): b<5 and c < 5, points.items()))
Method 4
>>> points = {'a': (3, 4), 'c': (5, 5), 'b': (1, 2), 'd': (3, 3)}
>>> dict(filter(lambda x: (x[1][0], x[1][1]) < (5, 5), points.items()))
{'a': (3, 4), 'b': (1, 2), 'd': (3, 3)}
Method 5
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)
Method 6
I think that Alex Martelli’s answer is definitely the most elegant way to do this, but just wanted to add a way to satisfy your want for a super awesome dictionary.filter(f) method in a Pythonic sort of way:
class FilterDict(dict):
def __init__(self, input_dict):
for key, value in input_dict.iteritems():
self[key] = value
def filter(self, criteria):
for key, value in self.items():
if (criteria(value)):
self.pop(key)
my_dict = FilterDict( {'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)} )
my_dict.filter(lambda x: x[0] < 5 and x[1] < 5)
Basically we create a class that inherits from dict, but adds the filter method. We do need to use .items() for the the filtering, since using .iteritems() while destructively iterating will raise exception.
Method 7
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0