-2

I have an arbitrary python dictionary x such that the values of each key is itself a list. Here is an example:

x = {"first_name": ["Mahmoud", "Pei-chi"], "second_name": ["Abadi", "Yao"]}

Given x I would like write a method that computes a list of dictionaries such that each dictionary has the same keys as x but the values are each combination of individual list element. So in this case, the result should be:

[{"first_name": "Mahmoud", "second_name": "Abadi"}, 
 {"first_name": "Mahmoud", "second_name": "Yao"}, 
 {"first_name": "Pei-chi", "second_name": "Abadi"}, 
 {"first_name": "Pei-chi", "second_name": "Yao"}]

How can I do it? The dictionary x may have any arbitrary number of keys with arbitrary names.

Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • This is definitely a better formulation of your problem. What would've been ideal would be to include your efforts, what you've tried as well. – cs95 Nov 08 '17 at 08:44
  • 1
    Can we assume that the order of the four dictionaries in the result list does not matter? – timgeb Nov 08 '17 at 08:52

4 Answers4

2

You can issue the following list comprehension.

result = [dict(zip(x.keys(), t)) for t in product(*x.values())]
timgeb
  • 76,762
  • 20
  • 123
  • 145
  • Suppose `x` is an OrderedDict? I can easily convert it to one. Then how to do it? – Saqib Ali Nov 08 '17 at 08:56
  • Even before 3.7 made `dict` insertion ordered, `keys` and `values` were guaranteed to iterate in the same order as each other, [per the docs](https://docs.python.org/3.5/library/stdtypes.html#dictionary-view-objects): "If keys, values and items views are iterated over with no intervening modifications to the dictionary, the order of items will directly correspond" so you don't need the generator expression here to replicate the `keys` ordering. In 3.7+, the order is guaranteed to be insertion ordered, but even before then, it was guaranteed to be consistent. – ShadowRanger Mar 05 '19 at 19:19
  • @ShadowRanger is correct, I did not know this back in 2017. – timgeb Mar 07 '19 at 09:53
1

Python's itertools.product() is good for this:

from itertools import product

x = {"first_name": ["Mahmoud", "Pei-chi"], "second_name": ["Abadi", "Yao"]}
dict_list = [{'first_name': f, 'second_name':s} for f, s in product(x['first_name'], x['second_name'])]

Giving you:

[{'first_name': 'Mahmoud', 'second_name': 'Abadi'}, {'first_name': 'Mahmoud', 'second_name': 'Yao'}, {'first_name': 'Pei-chi', 'second_name': 'Abadi'}, {'first_name': 'Pei-chi', 'second_name': 'Yao'}]
Martin Evans
  • 45,791
  • 17
  • 81
  • 97
  • Yeah, but do you really want to hardcode the order of the keys you expect, especially for a large dictionary? – timgeb Nov 08 '17 at 08:48
0

If you start from basic operations on list and dictionary with this simple for loops you can do above operations, but yeah it's not as much optimized as of others in terms of neatness, nut complexity of operations is same.

    lis = []
    for f in x:
        if f =='first_name':
            for l in x[f]:
                for j in x['second_name']:
                    dic ={}
                    dic['first-name']=l;dic['last_name']=j
                    lis.append(dic)

O/P will be as we expect:

    [{'first-name': 'Mahmoud', 'last_name': 'Abadi'},
    {'first-name': 'Mahmoud', 'last_name': 'Yao'},
    {'first-name': 'Pei-chi', 'last_name': 'Abadi'},
    {'first-name': 'Pei-chi', 'last_name': 'Yao'}]
0

If your dict are unordered don't worry you can use ordered dict , it will not change the result, it will give the same result every time.

dict_1 = {"first_name": ["Mahmoud", "Pei-chi"], "second_name": ["Abadi", "Yao"]}

import itertools
import collections
from operator import itemgetter
ordered_dict=collections.OrderedDict(sorted(dict_1.items(), key=itemgetter(0)))

items=[]
for key,value in ordered_dict.items():
    items.append(value)
    print([{"first_name":item[0],"last_name" :item[1]} for item in itertools.product(*items, repeat=1) if len(item)>1])

output:

[{'first_name': 'Mahmoud', 'last_name': 'Abadi'}, {'first_name': 'Mahmoud', 'last_name': 'Yao'}, {'first_name': 'Pei-chi', 'last_name': 'Abadi'}, {'first_name': 'Pei-chi', 'last_name': 'Yao'}]
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88