views:

86

answers:

3

If a lot of nested dictionarys, I am trying to find a certain key.

this key is called "fruit". But it's nested inside somewhere. How do I find the value of this key?

+3  A: 

(Making some wild guesses about your data structure...)

Do it recursively:

def findkey(d, key):
    if key in d: return d[key]
    for k,subdict in d.iteritems():
        val = findkey(subdict, key)
        if val: return val
Marcelo Cantos
If any value that's not itself a dict is ever met in the recursion, this approach will try to index it, or call iteritems on that nondict, and thus fail quite peculiarly.
Alex Martelli
A: 

Just traverse the dictionary and check for the keys (note the comment in the bottom about the "not found" value).

def find_key_recursive(d, key):
  if key in d:
    return d[key]
  for k, v in d.iteritems():
    if type(v) is dict: # Only recurse if we hit a dict value
      value = find_key_recursive(v, key)
      if value:
        return value
  # You may want to return something else than the implicit None here (and change the tests above) if None is an expected value
Håvard S
that's not the way to check type of object. @jathanism: and what are the other possible ways of using recursive function?
SilentGhost
@SilentGhost updated to use the more appropriate is check.
Håvard S
Hmmm... instead of `type(v)` is `dict`, shouldn't you use `instanceof(v, dict)`? The former does not accept subclasses of `dict`. Also, if you check for the existence of `__contains__` instead, your code will also accept other objects that support the "in" operator, not just dicts.
Tamás
@Tamás You could also use `isinstance()`, yes. However, dict was a given in this case. The `__contains__` suggestion would not necessarily be right - think about what would happen if you hit a list with that approach, for instance.
Håvard S
@Håvard S: indeed you are right about the `__contains__` part, my bad.
Tamás
+2  A: 

@Håvard's recursive solution is probably going to be OK... unless the level of nesting is too high, and then you get a RuntimeError: maximum recursion depth exceeded. To remedy that, you can use the usual technique for recursion removal: keep your own stack of items to examine (as a list that's under your control). I.e.:

def find_key_nonrecursive(adict, key):
  stack = [adict]
  while stack:
    d = stack.pop()
    if key in d:
      return d[key]
    for k, v in d.iteritems():
      if isinstance(v, dict):
        stack.append(v)

The logic here is quite close to the recursive answer (except for checking for dict in the right way;-), with the obvious exception that the recursive calls are replaced with a while loop and .pop and .append operations on the explicit-stack list, stack.

Alex Martelli
Do you know exactly what the maximum recursion depth is? From what I understand it would have to be nested at least a 100 deep, but I'm not completely sure.
Goose Bumper
@Goose Bumper: `import sys; sys.getrecursionlimit()`. Also, `sys.setrecursionlimit()`
gorsky
@gorsky: thanks! For everyone, the recursion limit on my computer is 1000.
Goose Bumper