简体   繁体   中英

Converting python dictionary to unique key-value pairs

I want to convert a python dictionary to a list which contains all possible key-value pair. For example, if the dict is like:

{
    "x": {
            "a1": { "b": {
                            "c1": { "d": { "e1": {}, "e2": {} } },
                            "c2": { "d": { "e3": {}, "e4": {} } }
                        }
                },
            "a2": { "b": {
                            "c3": { "d": { "e1": {}, "e5": {} } },
                            "c4": { "d": { "e6": {} } }
                        }
                 }
       }
}

I would like to get a list like:

[
  { "x": "a1", "b": "c1", "d": "e1" },
  { "x": "a1", "b": "c1", "d": "e2" },
  { "x": "a1", "b": "c2", "d": "e3" },
  { "x": "a1", "b": "c2", "d": "e4" },
  { "x": "a2", "b": "c3", "d": "e1" },
  { "x": "a2", "b": "c3", "d": "e5" },
  { "x": "a2", "b": "c4", "d": "e6" }
]

I am struggling to write a recursive function. I have written this, but it is not working

def get_list(groups, partial_row):
    row = []
    for k, v in groups.items():
        if isinstance(v, dict):
            for k2, v2 in v.items():
                partial_row.update({k: k2})
                if isinstance(v2, dict):
                    row.extend(get_list(v2, partial_row))
                else:
                    row.append(partial_row)

    return row

Alternative solution:

from pprint import pprint
dic = {
    "x": {
            "a1": { "b": {
                            "c1": { "d": { "e1": {}, "e2": {} } },
                            "c2": { "d": { "e3": {}, "e4": {} } }
                        }
                },
            "a2": { "b": {
                            "c3": { "d": { "e1": {}, "e5": {} } },
                            "c4": { "d": { "e6": {} } }
                        }
                 }
       }
}


def rec(dic, path=[], all_results=[]):
    if not dic:
        # No items in the dictionary left, add the path
        # up to this point to all_results

        # This is based on the assumption that there is an even
        # number of items in the path, otherwise you output format
        # makes no sense
        even_items = path[::2]
        odd_items = path[1::2]
        result = dict(zip(even_items, odd_items))
        all_results.append(result)
        return all_results

    for key in dic:
        # Make a copy of the current path
        path_cp = list(path)
        path_cp.append(key)
        all_results = rec(dic[key], path_cp, all_results)

    return all_results


results = rec(dic)

pprint(results)

Output:

[{'b': 'c2', 'd': 'e4', 'x': 'a1'},
 {'b': 'c2', 'd': 'e3', 'x': 'a1'},
 {'b': 'c1', 'd': 'e1', 'x': 'a1'},
 {'b': 'c1', 'd': 'e2', 'x': 'a1'},
 {'b': 'c3', 'd': 'e5', 'x': 'a2'},
 {'b': 'c3', 'd': 'e1', 'x': 'a2'},
 {'b': 'c4', 'd': 'e6', 'x': 'a2'}]
a = {
"x": {
    "a1": { "b": {
                    "c1": { "d": { "e1": {}, "e2": {} } },
                    "c2": { "d": { "e3": {}, "e4": {} } }
                }
        },
    "a2": { "b": {
                    "c3": { "d": { "e1": {}, "e5": {} } },
                    "c4": { "d": { "e6": {} } }
                }
         }
}
}


def print_dict(d, depth, *arg):
    if type(d) == dict and len(d):
        for key in d:
            if not len(arg):
                new_arg = key
            else:
                new_arg = arg[0] + (': ' if depth % 2 else ', ') + key
            print_dict(d[key], depth+1, new_arg)
    else:
        print(arg[0])

print_dict(a, depth=0)

Result:

x: a1, b: c1, d: e1
x: a1, b: c1, d: e2
x: a1, b: c2, d: e4
x: a1, b: c2, d: e3
x: a2, b: c4, d: e6
x: a2, b: c3, d: e1
x: a2, b: c3, d: e5

You are missing one condition check in the following section in your original solution:

if isinstance(v2, dict):
    row.extend(get_list(v2, partial_row))
else:
    row.append(partial_row)

Rather it has to be

if isinstance(v2, dict) and v2:
    row.extend(get_list(v2, partial_row))
else:
    row.append(partial_row)

Due to the missing and v2 , the else block never gets executed and you are always getting the empty list as a result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM