简体   繁体   中英

How to combine two lists of tuples to create a nested dictionary?

I have two lists of tuples like:

tin = [
       ('a1', 'meow'),
       ('b1', 'woof'),
       ('c1', 'mooo'),
       ('d1', 'oink'),
      ]



rop = [
       ('b1', 'forest'),
       ('a1', 'home'),
       ('d1', 'shed'),
      ]

How can I combine them into one dictionary so that the result looks like:

full = [
        {'a1' : {'sound': 'meow',
                 'place': 'home'}

        {'b1' : {'sound': 'woof',
                 'place': 'forest'}

        {'c1' : {'sound': 'mooo',
                 'place': None}

        {'d1' : {'sound': 'oink',
                 'place': 'shed'}
       ]

I have it working like this:

    my_dict = {}

    for k, v in tin :

        if not my_dict.get(k):
            my_dict[k] = {}
            my_dict[k]['sound'] = v 

        else:
            my_dict[k]['sound'] = v 

    for k, v in rop:

        if not my_dict.get(k):
            my_dict[k] = {}
            my_dict[k]['place'] = v 

        else:
            my_dict[k]['place'] = v 

But is is very verbose and I think there should be something more pythonic.

Are you sure you want full as a list? If you say it should be one dict , then it should be something like this:

{
 'a1': {'place': 'home',   'sound': 'meow'},
 'b1': {'place': 'forest', 'sound': 'woof'},
 'c1': {'place': None,     'sound': 'mooo'},
 'd1': {'place': 'shed',   'sound': 'oink'}
}

which is produced by the following code:

# note: converting tin and rop to dict:
tin = dict(tin)
rop = dict(rop)

full = {}
for k in set(tin.keys()) | set(rop.keys()):
    full[k] = {'sound': tin.get(k, None), 'place': rop.get(k, None)}

By the way, if you really want a list of dicts, use this instead:

full = []
for k in set(tin.keys()) | set(rop.keys()):
    full.append({k: {'sound': tin.get(k, None), 'place': rop.get(k, None)}})

Using a simple iteration.

Demo:

tin = [
       ('a1', 'meow'),
       ('b1', 'woof'),
       ('c1', 'mooo'),
       ('d1', 'oink'),
      ]

rop = [
       ('b1', 'forest'),
       ('a1', 'home'),
       ('d1', 'shed'),
      ]

rop = dict(rop)    #Convert to dict for easy key-value access

d = {}
for i, v in tin:
    d[i] = {'sound': v, 'place': rop.get(i, None)}
print(d)

Output:

{'a1': {'sound': 'meow', 'place': 'home'}, 'c1': {'sound': 'mooo', 'place': None}, 'b1': {'sound': 'woof', 'place': 'forest'}, 'd1': {'sound': 'oink', 'place': 'shed'}}

You can use itertools.groupby :

import itertools
tin = [('a1', 'meow'), ('b1', 'woof'), ('c1', 'mooo'), ('d1', 'oink')]
rop = [('b1', 'forest'), ('a1', 'home'), ('d1', 'shed')]
sounds = ['woof', 'mooo', 'oink']
places = ['forest', 'home', 'shed']
new_s = {a:[i for _, i in b] for a, b in itertools.groupby(sorted(tin+rop, key=lambda x:x[0]), key=lambda x:x[0])} 
final_s = {a:dict(zip(['sound', 'place'], b if len(b) == 2 else [None]+b if b[0] in places else b+[None])) for a, b in new_s.items()}

Output:

{'a1': {'sound': 'meow', 'place': 'home'}, 'b1': {'sound': 'woof', 'place': 'forest'}, 'c1': {'sound': 'mooo', 'place': None}, 'd1': {'sound': 'oink', 'place': 'shed'}}

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