How do I traverse and search a python dictionary?

前端 未结 7 1012
逝去的感伤
逝去的感伤 2020-12-04 18:52

I have nested dictionaries:

{\'key0\': {\'attrs\': {\'entity\': \'p\', \'hash\': \'34nj3h43b4n3\', \'id\': \'4130\'},
          u\'key1\': {\'attrs\': {\'ent         


        
相关标签:
7条回答
  • 2020-12-04 18:56

    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}
    
    0 讨论(0)
  • 2020-12-04 18:57

    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.

    0 讨论(0)
  • 2020-12-04 19:01

    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

    0 讨论(0)
  • 2020-12-04 19:04

    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...
    
    0 讨论(0)
  • 2020-12-04 19:17

    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.

    0 讨论(0)
  • 2020-12-04 19:22

    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'] )
    
    0 讨论(0)
提交回复
热议问题