简体   繁体   中英

dict from a dict of list

I have a Python dictionary with following format:

d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'],
      'Element2':['1','2','3']}

Expected output:

{'Name': 'ABC', 'Number': '123',
 'Elements': [{'Element 1': '1', 'Element2': '1'},
              {'Element 1': '2', 'Element2': '2'},
              {'Element 1': '3', 'Element2': '3'}]

I have tried the following:

[{k: v[i] for k, v in d1.items() if i < len(v)}
    for i in range(max([len(l) for l in d1.values()]))]

but getting this result:

[{'Name': 'ABC', 'Number': '123', 'Element 1': '1', 'Element 2': '1'},
 {'Element 1': '2', 'Element 2': '2'},
 {'Element 1': '3', 'Element 2': '3'}]

How can I go from here?

I strongly recommend not trying to do everything in one line. It's not always more efficient, and almost always less readable if you have any branching logic or nested loops.

Given your dict, we can pop() the Name and Number keys into our new dict. Then

output = dict()

d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'], 'Element2':['1','2','3']}

output["Name"] = d1.pop("Name")
output["Number"] = d1.pop("Number")

print(output)
# prints:
# {'Name': ['ABC'], 'Number': ['123']}

print(d1)
# prints:
# {'Element 1': ['1', '2', '3'], 'Element2': ['1', '2', '3']}

Then, we zip all remaining values in the dictionary, and add them to a new list:

mylist = []
keys = d1.keys()

for vals in zip(*d1.values()):
    temp_obj = dict(zip(keys, vals))
    mylist.append(temp_obj)

print(mylist)
# prints: 
# [{'Element 1': '1', 'Element2': '1'},
#  {'Element 1': '2', 'Element2': '2'},
#  {'Element 1': '3', 'Element2': '3'}]

And finally, assign that to output["Elements"]

output["Elements"] = mylist
print(output)
# prints:
# {'Name': ['ABC'], 'Number': ['123'], 'Elements': [{'Element 1': '1', 'Element2': '1'}, {'Element 1': '2', 'Element2': '2'}, {'Element 1': '3', 'Element2': '3'}]}

Since you don't want to hardcode the first two keys,

for k, v in d1.items():
    if "element" not in k.lower():
        output[k] = v

Or as a dict-comprehension:

output = {k: v for k, v in d1.items() if "element" not in k.lower()}

use a list of tuples to create the elements list of dictionaries. Use Convert to build your dictionary item from the tuple.

#https://www.geeksforgeeks.org/python-convert-list-tuples-dictionary/

d1 = {'Name':['ABC'], 'Number':['123'], 'Element 1':['1', '2', '3'],
  'Element2':['1','2','3']}

def Convert(tup, di):
    for a, b in tup:
       di[a]=b
    return di

dict={}
listElements=[]
for key,value in d1.items():
   if isinstance(value,list) and len(value)>1:
       for item in value:
           listElements.append((key,item))
   elif isinstance(value,list) and len(value)==1:
       dict[key]=value[0]
   else:
       dict[key]=value
    
 dict['Elements']=[Convert([(x,y)],{})  for x,y in listElements]
 print(dict)  

output:

 {'Name': 'ABC', 'Number': '123', 'Elements': [{'Element 1': '1'}, {'Element 1': '2'}, {'Element 1': '3'}, {'Element2': '1'}, {'Element2': '2'}, {'Element2': '3'}]}  

I'm going to explain step by step:

  1. We build new_d1 variable, that is the dictionary you expect as output and it's initialized as {'Name': 'ABC', 'Number': '123'} . For achieving the above, we use comprehension notation taking into account the keys != 'Element'

     new_d1 = {key: d1.get(key)[0] for key in filter(lambda x: 'Element' not in x, d1)}
  2. We build elements variable, that's a list with the dictionaries matter for us, I mean, the dictionaries we have to manipulate to achieve the expected result. Then elements is [{'Element 1': ['1', '2', '3']}, {'Element2': ['1', '2', '3']}] .

     elements = [{key: d1.get(key)} for key in filter(lambda x: 'Element' in x, d1)]
  3. We are going to do a Cartesian product using itertools.product taking into account each key and each item of the values present in elements .

     product = [list(it.product(d.keys(), *d.values())) for d in elements]
  4. Using zip , we arrange the data and covert them in dictionary. And finally we create "Elements" key in new_df1

    elements_list = [dict(t) for index, t in enumerate(list(zip(*product)))] new_d1["Elements"] = elements_list print(new_d1)

Full code:

import itertools as it

new_d1 = {key: d1.get(key)[0] for key in filter(lambda x: 'Element' not in x, d1)}
elements = [{key: d1.get(key)} for key in filter(lambda x: 'Element' in x, d1)]
product = [list(it.product(d.keys(), *d.values())) for d in elements]
elements_list = [dict(t) for index, t in enumerate(list(zip(*product)))]
new_d1["Elements"] = elements_list

Output:

{'Elements': [{'Element 1': '1', 'Element2': '1'},
              {'Element 1': '2', 'Element2': '2'},
              {'Element 1': '3', 'Element2': '3'}],
 'Name': 'ABC',
 'Number': '123'}

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