StackOverFlow1132
StackOverFlow1132

Reputation: 35

python unpack nested dictionary and store keys and values in tuples

If I have something like this:

dic = {"hi": 5, "test": {"apple": 2, "orange": 3}, "sa": "ok"}

and I want my output to be like this:

[("hi", 5), ("apple", 2), ("orange": 3), ("sa", "ok")]

with each key and value beside each other. I ignored the "test" key in the final output because it's value is a dictionary.

Upvotes: 0

Views: 1885

Answers (5)

Snedecor
Snedecor

Reputation: 739

I think the best approach to solve this kind of problem is through recursion, just in case you face something very weird. For example a dictionary in a dictionary in a dictionary (dictionaryception) /s.

def flattenDict(aDict):
    result = []
    for i in aDict: #we iterate through the dictionary
        if isinstance(aDict[i], dict): #if the value of the key is a dictionary
            result.extend(flattenDict(aDict[i])) #recursion
        else:
            result.append((i, aDict[i])) #else we append the value in the result list.
    return result

Output:

[('hi', 5), ('apple', 2), ('orange', 3), ('sa', 'ok')]

Upvotes: 1

Lynxy
Lynxy

Reputation: 25

Here is a proposition of how you can handle that, assuming ("orange": 3) in the output is instead ("orange", 3) :

def work(di):
    def f(di):
        for i in di:
            if isinstance(di[i],dict):
                yield f(di[i])
            else:
                yield (i,di[i])               
    result = [] 
    for item in f(di):
        result+=[item] if isinstance(item,tuple) else list(item)
    return result

dic = {"hi": 5, "test": {"apple": 2, "orange": 3}, "sa": "ok"}
print(work(dic))

#Output
[('hi', 5), ('apple', 2), ('orange', 3), ('sa', 'ok')]

Upvotes: 0

If ("orange": 3) in the expected result in the original question is a typo and your desired result is a list of tuples, the simplest answer may be:

dic = {"hi": 5, "test": {"apple": 2, "orange": 3}, "sa": "ok"}

l = []

for key in dic.keys():
    if isinstance(dic[key], dict):
        l.extend(dic[key].items())
        continue

    l.append((key, dic[key]))

print l

results:

[('orange', 3), ('apple', 2), ('sa', 'ok'), ('hi', 5)]

Upvotes: 0

DYZ
DYZ

Reputation: 57033

A recursive solution:

from itertools import chain
def flatten(d):
    return chain.from_iterable([(k,v)] if not isinstance(v,dict) else flatten(v) 
                               for k,v in d.items())
list(flatten(dic))
#[('hi', 5), ('apple', 2), ('orange', 3), ('sa', 'ok')]

Upvotes: 1

Chinny84
Chinny84

Reputation: 966

A possible solution, which solves just two levels of nesting (As above) is the following.

  def loop_dict(d: dict):
      """continue to pop until no more dict d"""
      while d:
          yield d.popitem()

 output = []
 for k, v in loop_dict(dic):
     if type(v) == dict:
         output.extend(loop_dict(v))
     else:
         output.append((k, v))

To go further you can implement some recursive calls. Which will basically go depth to find the deepest nest and propagate backwards.

Upvotes: 0

Related Questions