5

I'm new in Python and I am not sure it is a good idea to use dict of dict but here is my question. I have a dictionary of dictionaries and I want to filter by the key of the inside dict:

a = { 'key1' : {'id1' :[0,1,2] , 'id2' :[0,1,2], 'id3' :[4,5,6]},
     'key2' : {'id3' :[0,1,2] , 'id4' :[0,1,2]},
     'key3' : {'id3' :[0,1,2] , 'id1' :[4,5,6]}
   }

For exemple , I want to filter by 'id1' to have :

result = { 'key1' : {'id1' :[0,1,2] },
           'key3' : {'id1' :[4,5,6]}
         }

I have tried the filter method by I get all the value:

r = [('key1' ,{'id1' :[0,1,2] , 'id2' :[0,1,2], 'id3' :[4,5,6]}),
     ('key3' , {'id3' :[0,1,2] , 'id1' :[4,5,6]})
   ]

Furthermore the filter method returns a list and I want to keep the format as a dict.

Thanks in advance

Lod
  • 657
  • 1
  • 9
  • 30
Othman
  • 332
  • 5
  • 19
  • I think you need to use some data processing technique. Given your output specification you probably need use custom objects. – Pwnna May 13 '11 at 13:36

4 Answers4

6

Try this:

>>> { k: v['id1'] for k,v in a.items() if 'id1' in v }
{'key3': [4, 5, 6], 'key1': [0, 1, 2]}

For Python 2.x you might prefer to use iteritems() instead of items() and you'll still need a pretty recent python (2.7 I think) for a dictionary comprehension: for older pythons use:

dict((k, v['id1']) for k,v in a.iteritems() if 'id1' in v )

If you want to extract multiple values then I think you are best to just write the loops out in full:

def query(data, wanted):
    result = {}
    for k, v in data.items():
        v2 = { k2:v[k2] for k2 in wanted if k2 in v }
        if v2:
            result[k] = v2
    return result

giving:

>>> query(a, ('id1', 'id2'))
{'key3': {'id1': [4, 5, 6]}, 'key1': {'id2': [0, 1, 2], 'id1': [0, 1, 2]}}
martineau
  • 119,623
  • 25
  • 170
  • 301
Duncan
  • 92,073
  • 11
  • 122
  • 156
  • this works great but actually I don't want to filter over only one value but a list value (eg. ['id1,'id2']) – Othman May 13 '11 at 13:58
2

According to the precision you gave to Duncan, here is another filtering on a list using dictionary comprehension:

>>> my_list = ['id1', 'id2']
>>> {k1 : {k2: v2 for (k2, v2) in a[k1].iteritems() if k2 in my_list} for k1 in a}
{'key3': {'id1': [4, 5, 6]}, 'key2': {}, 'key1': {'id2': [0, 1, 2], 'id1': [0, 1, 2]}}

EDIT: you can also remove empty values with another dict compreehension, but that "begins" to be difficult to read... :-)

>>> {k3: v3 for k3, v3 in {k1 : {k2: v2 for (k2, v2) in a[k1].iteritems() if k2 in my_list} for k1 in a}.iteritems() if v3}
{'key3': {'id1': [4, 5, 6]}, 'key1': {'id2': [0, 1, 2], 'id1': [0, 1, 2]}}
Emmanuel
  • 13,935
  • 12
  • 50
  • 72
  • pity about that empty dictionary lurking in the middle. I think at that point it is worth giving up on dictionary comprehensions and just write everything out in full: see my updated answer – Duncan May 13 '11 at 14:23
1

You can do with a dictionary comprehension:

def query(data, query):
    return {key : {query : data[key][query]} 
            for key in data if query in data[key]}

You have to look at each entry of the dictionary, which can cost a lot of time if you have many entries or do this a lot. A database with a index can speed this up.

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
1
field = 'id1'
dict( (k,{field: d[field]}) for k,d in a.items() if field in d)
martineau
  • 119,623
  • 25
  • 170
  • 301
vartec
  • 131,205
  • 36
  • 218
  • 244