I just learned about list comprehension, which is a great fast way to get data in a single line of code. But something's bugging me.
In my test I have this kind of dictionaries inside the list:
[{'y': 72, 'x': 94, 'fname': 'test1420'}, {'y': 72, 'x': 94, 'fname': 'test277'}]
The list comprehension s = [ r for r in list if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ]
works perfectly on that (it is, in fact, the result of this line)
Anyway, I then realised I'm not really using a list in my other project, I'm using a dictionary. Like so:
{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}}
That way I can simply edit my dictionary with var['test1420'] = ...
But list comprehensions don't work on that!
And I can't edit lists this way because you can't assign an index like that.
Is there another way?
You can do this:
s = dict([ (k,r) for k,r in mydict.iteritems() if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ])
This takes a dict as you specified and returns a 'filtered' dict.
If dct
is
{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
'test277': {'y': 72, 'x': 94, 'fname': 'test277'},}
Perhaps you are looking for something like:
[ subdct for key,subdct in dct.iteritems()
if 92<subdct['x']<95 and 70<subdct['y']<75 ]
A little nicety is that Python allows you to chain inequalities:
92<dct[key]['x']<95
instead of
if r['x'] > 92 and r['x'] < 95
Note also that above I've written a list comprehension, so you get back a list (in this case, of dicts).
In Python3 there are such things as dict comprehensions as well:
{ n: n*n for n in range(5) } # dict comprehension
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
In Python2 the equivalent would be
dict( (n,n*n) for n in range(5) )
I'm not sure if you are looking for a list of dicts or a dict of dicts, but if you understand the examples above, it is easy to modify my answer to get what you want.
Sounds like you want something like:
my_dict = {'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
'test277' : {'y': '072', 'x': '094', 'fname': 'test277'}}
new_dict = dict((k,v) for k,v in my_dict.items()
if 92 < int(v['x']) < 95 and 70 < int(v['y']) < 75)
Some notes on this code:
- I'm using a generator expression
instead of a list comprehension
- Python lets you combine inequality
tests as
low < value < high
- The dict() constructor takes an iterable
of key/value tuples to create a
dictionary
You can get a list of the values of a dictionary d with d.values()
. Your list comprehension should work using that, although I'm a little unclear what exactly you want the output to be.
Is there another way?
Why not consider the use of some lightweight objects?
You can still use list comprehensions for gathering or filtering the objects, and gain a lot in clarity / extensibility.
>>> class Item(object):
... def __init__(self, x, y, name):
... self.x = x
... self.y = y
... self.name = name
...
>>> list_items = []
>>> list_items.append(Item(x=70, y=60, name='test1420'))
>>> list_items.append(Item(x=94, y=72, name='test277'))
>>> items_matching = [item for item in list_items
if 92 < item.x < 95 and 70 < item.y < 75]
>>> for item in items_matching:
... print item.name
...
test277
>>> first_item = items_matching[0]
>>> first_item.x += 50
>>> first_item.x
144