List of tuples to nested dictionary without overri

2019-09-14 10:16发布

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?

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-09-14 10:49

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',)}}}
查看更多
贼婆χ
3楼-- · 2019-09-14 10:51

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',)}}}
查看更多
登录 后发表回答