I have nested dictionaries:
{\'key0\': {\'attrs\': {\'entity\': \'p\', \'hash\': \'34nj3h43b4n3\', \'id\': \'4130\'},
u\'key1\': {\'attrs\': {\'ent
If you want to solve the problem in a general way, no matter how many level of nesting you have in your dict, then create a recursive function which will traverse the tree:
def traverse_tree(dictionary, id=None):
for key, value in dictionary.items():
if key == 'id':
if value == id:
print dictionary
else:
traverse_tree(value, id)
return
>>> traverse_tree({1: {'id': 2}, 2: {'id': 3}}, id=2)
{'id': 2}
This is an old question but still a top google result, so I'll update:
A friend and myself published a library to solve (very nearly) this exact problem. dpath-python (no relation to the perl dpath module which does similar things).
http://github.com/akesterson/dpath-python
All you would need to do is something like this:
$ easy_install dpath
>>> import dpath.util
>>> results = []
>>> for (path, value) in dpath.util.search(my_dictionary, "*/attrs/entity/4130*", yielded=True):
>>> ... parent = dpath.util.search("/".join(path.split("/")[:-2])
>>> ... results.append(parent)
... that would give you a list of all the dictionary objects that matched your search, i.e., all the objects that had (key = 4130*). The parent bit is a little janky, but it would work.
I believe pydash will give you the most efficient way to achieve this.
For example:
data = {'a': {'b': {'c': [0, 0, {'d': [0, {1: 2}]}]}}, 'names': {'first': 'gus', 'second': 'parvez'}}
pydash.get(data, 'a.b.c.2.d.1.[1]')
# output: 2
Detail documentation you can find here: https://pydash.readthedocs.io/en/latest/quickstart.html
Your structure is unpleasantly irregular. Here's a version with a Visitor function that traverses the attrs
sub-dictionaries.
def walkDict( aDict, visitor, path=() ):
for k in aDict:
if k == 'attrs':
visitor( path, aDict[k] )
elif type(aDict[k]) != dict:
pass
else:
walkDict( aDict[k], visitor, path+(k,) )
def printMe( path, element ):
print path, element
def filterFor( path, element ):
if element['id'] == '4130-2-2':
print path, element
You'd use it like this.
walkDict( myDict, filterFor )
This can be turned into a generator instead of a Visitor; it would yield path, aDict[k]
instead of invoking the visitor function.
You'd use it in a for loop.
for path, attrDict in walkDictIter( aDict ):
# process attrDict...
Well, if you have to do it only a few times, you can just use nested dict.iteritems() to find what you are looking for.
If you plan to do it several times, performances will quickly becomes an issue. In that case you could :
change the way you data is returned to you to something more suitable.
if you can't, convert the data once the fly to a dict between id and keys (using iteritems). Then use it.
This kind of problem is often better solved with proper class definitions, not generic dictionaries.
class ProperObject( object ):
"""A proper class definition for each "attr" dictionary."""
def __init__( self, path, attrDict ):
self.path= path
self.__dict__.update( attrDict )
def __str__( self ):
return "path %r, entity %r, hash %r, id %r" % (
self.path, self.entity, self.hash, self.id )
masterDict= {}
def builder( path, element ):
masterDict[path]= ProperObject( path, element )
# Use the Visitor to build ProperObjects for each "attr"
walkDict( myDict, builder )
# Now that we have a simple dictionary of Proper Objects, things are simple
for k,v in masterDict.items():
if v.id == '4130-2-2':
print v
Also, now that you have Proper Object definitions, you can do the following
# Create an "index" of your ProperObjects
import collections
byId= collections.defaultdict(list)
for k in masterDict:
byId[masterDict[k].id].append( masterDict[k] )
# Look up a particular item in the index
print map( str, byId['4130-2-2'] )