简体   繁体   中英

List of tuples to nested dictionary without overriding

I need to convert the above list of tuples to nested dictionary without overwriting the value as below in python

[('a', '1'),
  ('b', 'true'),
  ('b', 'none'),
  ('a', '2'),
  ('b', 'true'),
  ('a', '3'),
  ('b', 'false')]


{'a': {'1' : { 'b' : ('true','none')},
       '2' : { 'b' : ('true')},
       '3' : { 'b' : ('false')}}}

Converting each tuple into dictionary using

dict()

and merging the dictionary doesn't work. Is there any pythonic way to do this?

Here's one way to do it with collections.defaultdict :

from collections import defaultdict
import pprint

data = [('a', '1'), ('b', 'true'), ('b', 'none'), ('a', '2'), ('b', 'true'), ('a', '3'), ('b', 'false')]

d = defaultdict(lambda: defaultdict(lambda: defaultdict(tuple)))    
for i, j in data:
    if i == 'a':
        p = d[i][j]
    else:
        p[i] += j,

pprint.pprint(d)
# {'a': {'1': defaultdict(<class 'tuple'>, {'b': ('true', 'none')}),
#        '2': defaultdict(<class 'tuple'>, {'b': ('true',)}),
#        '3': defaultdict(<class 'tuple'>, {'b': ('false',)})}}

You could also use the dictionary's setdefault method to return default values for new keys, although the defaultdict approach is much cleaner and faster:

c = {}
for i, j in data:
    if i == 'a':
        q = c.setdefault(i, {}).setdefault(j, {})
    else:
        q[i] = q.setdefault(i, ()) + (j,)

pprint.pprint(c)
# {'a': {'1': {'b': ('true', 'none')},
#        '2': {'b': ('true',)},
#        '3': {'b': ('false',)}}}

Expanding @MosesKoledoye answer, if the first value in the dictionary is only 'a' and 'b' , you know that the outer dictionary will always contain at most one element using 'a' as the key and the inner dictionary will always contain at most one element using 'b' as the key. So in the end you get the same information if it is {'1': ('true', 'none')… . You can convert that to your format simply by wrapping the data in some dictionaries. This means you can do the following

output = defaultdict(tuple)
for i, j in data:
    if i == 'a':
        current = j
    else:
        # i == 'b'
        output[current] += (j, )

This will result in the following:

defaultdict(<type 'tuple'>, {'1': ('true', 'none'), '3': ('false',), '2': ('true',)})

Now to get it into a dictionary like yours you can do the following:

output = {k: {'b': v} for k, v in output.items()}
if output:
    output = {'a': output}

Resulting in the following:

{'a': {'1': {'b': ('true', 'none')}, '3': {'b': ('false',)}, '2': {'b': ('true',)}}}

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