Tzach
Tzach

Reputation: 13376

Find in dict of dicts based on value

I have a dict of dicts:

d = {
    "key1" : {"id" : 5},
    "key2" : {"id" : 6},
}

What is the most pythonic way of finding some (doesn't matter which) key in this dict that it's value has a specific key / value pair? In my example I would like something like:

result = find_by_key(d, "id", 5) # should return "key1"

Upvotes: 0

Views: 132

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121554

Using a generator expression and the next() function:

def find_by_key(d, key, value):
    try:
        return next(k for k, v in d.iteritems() if (key, value) in v.viewitems())
    except StopIteration:
        raise KeyError

I assumed you wanted a KeyError if no matching dictionary is found.

The generator expression filters the dictionary on values that have the key-value pair, as determined by a membership test against the dictionary items view.

This does the minimal amount of work to locate a matching key.

Variations:

  • In Python 3 dict.items() is already a view, and iteritems() has been ditched, so use dict.items() instead:

    return next(k for k, v in d.items() if (key, value) in v.items())
    
  • If you want to return a default instead of raising a key error you can have next() return it:

    def find_by_key(d, key, value):
        return next(
            (k for k, v in d.iteritems() if (key, value) in v.viewitems()),
            None)
    

Demo:

>>> def find_by_key(d, key, value):
...     try:
...         return next(k for k, v in d.iteritems() if (key, value) in v.viewitems())
...     except StopIteration:
...         raise KeyError
... 
>>> d = {
...     "key1" : {"id" : 5},
...     "key2" : {"id" : 6},
... }
>>> find_by_key(d, "id", 5)
'key1'
>>> find_by_key(d, "id", 6)
'key2'
>>> find_by_key(d, "id", 7)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in find_by_key
KeyError

Upvotes: 5

Related Questions