5

I'm trying to create a recursive function that takes a JSON dictionary and stores any value with key names 'rate' into a list. I will then take that list and find the lowest value. My code looks like this right now, but is producing multiple empty lists within the list.

def recurse_keys(df):
    rates = []
    for key, value in df.items():
        if key == 'rate':
            rates.append(value)
        if isinstance(df[key], dict):
            recurse_keys(df[key])
Casey
  • 2,611
  • 6
  • 34
  • 60

4 Answers4

17

You need to combine the results from the recursion, and return it:

def recurse_keys(df):
    rates = []
    for key, value in df.items():
        if key == 'rate':
            rates.append(value)
        if isinstance(df[key], dict):
            rates += recurse_keys(df[key])
    return rates
Fabricator
  • 12,722
  • 2
  • 27
  • 40
  • 1
    @Casey `df[key]` and `value` are the same, no? Is there a reason to mix? – Jason Feb 01 '16 at 07:47
  • @Fabricator is this method preferred over the suggested below (passing `rates`)? This method would seem less intuitive, but maybe I'm wrong? – Jason Feb 01 '16 at 07:49
  • 1
    @Jason, both methods work. I prefer to use fewer arguments. Plus this required minimum change from OP's original code. – Fabricator Feb 01 '16 at 07:56
  • @Jason I think you are right. They are the same value. I'll fix that. – Casey Feb 01 '16 at 09:05
2
  1. extend your result list with the result from the recursive call
  2. don't forget to return your result

Code:

def recurse_keys(df):
    rates = []
    for key, value in df.items():
        if key == 'rate':
            rates.append(value)
        if isinstance(df[key], dict):
            rates += recurse_keys(df[key])
    return rates
timgeb
  • 76,762
  • 20
  • 123
  • 145
1

You can also initialize the rates list outside of the recursive function and pass it to the function, as list is a mutable datastructure, it'll be passed as reference. Like this (not tested though):

def recurse_keys(df, rates):
    for key, value in df.items():
        if key == 'rate':
            rates.append(value)
        if isinstance(df[key], dict):
            recurse_keys(df[key], rates)

def calling_method():
    rates = [] 
    recurse_keys(df, rates)
ferdy
  • 7,366
  • 3
  • 35
  • 46
0

you need pass rates as rates, it seems in every recursion you do create new rates list.

def recurse_keys(df, rates=[]):
    for key, value in df.items():
        if key == 'rate':
            rates.append(value)
        if isinstance(df[key], dict):
            recurse_keys(df[key], rates)
    return rates

result = recurse_keys(df)
min(result)
FatmaT
  • 255
  • 1
  • 9
  • 1
    be very careful about that mutable default argument – timgeb Feb 01 '16 at 07:43
  • 1
    Please check http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument. – Łukasz Rogalski Feb 01 '16 at 07:53
  • I have never faced problem with this usage but it does not mean I will not indeed, thanks @Rogalski, @ timgeb. I will be more careful. – FatmaT Feb 02 '16 at 07:45
  • @ŁukaszRogalski I checked that and several other pages linked in there! it made me realise that in this example simply calling `recurse_keys(df[key])` instead of `recurse_keys(df[key], rates)` would still work, but only the first time it is called. – Mozak May 05 '22 at 15:54