2

I am trying to create a list of dictionary with the lists below.

a = [["Name","Mary","Tom","John"],["Age","21","23","12"],["Gender","F","M","M"]]

I would like the output to be:

a_list=[{"Name":"Mary", "Age":"21", "Gender":"F"},{"Name":"Tom", "Age":"23", "Gender":"M"},{"Name":"John", "Age":"12", "Gender":"M"}]

I tried to use zip but could not get it to work. Please help!

3
  • what've you tried? Commented Nov 6, 2018 at 20:32
  • did you read, experiment and groke docs.python.org/3/library/functions.html#zip ? Commented Nov 6, 2018 at 20:37
  • I'm only upvoting because I googled "python dict zip Something About Mary" and this was the first result Commented Aug 28, 2019 at 6:41

7 Answers 7

8

First we can pull the header entries out so we're left with just the values:

headers, values = zip(*((x[0], x[1:]) for x in a))
print(headers, values)
# ('Name', 'Age', 'Gender') (['Mary', 'Tom', 'John'], ['21', '23', '12'], ['F', 'M', 'M'])

Then we can zip together the values, then zip each of those triples with headers to form the dictionaries:

print([dict(zip(headers, triple)) for triple in zip(*values)])
# [{'Name': 'Mary', 'Age': '21', 'Gender': 'F'}, {'Name': 'Tom', 'Age': '23', 'Gender': 'M'}, {'Name': 'John', 'Age': '12', 'Gender': 'M'}]
Sign up to request clarification or add additional context in comments.

4 Comments

@Usernamenotfound I included a broad strokes explanation in the answer, which specific part needs more?
Can you explain what the * operator does here along with zip?
@Usernamenotfound The * in this context is argument unpacking. It "unpacks" some iterable of arguments into individual arguments to the function. So zip(*[[1, 2], [3, 4]]) is the same as zip([1, 2], [3, 4]).
The last alternative on my answer shows a variation of your answer where you don't need the slicing on the first zip and can therefore get rid of zip(*values).
4
a_list = []
for i in range(1, len(a[0])):
    diction = {}
    diction[a[0][0]] = a[0][i]
    diction[a[1][0]] = a[1][i]
    diction[a[2][0]] = a[2][i]
    a_list.append(diction)

Comments

3
list(map(dict, zip(*([(k, i) for i in v] for k, *v in a))))

This returns:

[{'Name': 'Mary', 'Age': '21', 'Gender': 'F'}, {'Name': 'Tom', 'Age': '23', 'Gender': 'M'}, {'Name': 'John', 'Age': '12', 'Gender': 'M'}]

2 Comments

Amazing! Thank you all!
Shorter one-liner: [dict(zip(k, v)) for k, *zv in [zip(*a)] for v in zv] :)
3

Here is a simple solution that I would recommend:

zipped_a = zip(*a)
keys = next(zipped_a)
dicts = [dict(zip(keys, values)) for values in zipped_a]

Another way to pull keys out of the a_zipped iterator is by using it in nested loops. The first iteration of the outer loop grabs the keys, while the inerloop grabs each set of values. Unfortunately, this approach is not obvious on first glance:

a_zipped = zip(*a)
dicts = [dict(zip(keys, values)) for keys in a_zipped for values in a_zipped]

And yet another way to pull out keys from zip(*a) is to use iterable unpacking. It's clear, but it does create an extra list (all_values):

keys, *all_values = zip(*a)
dicts = [dict(zip(keys, values)) for values in all_values]

An then there's this silly one-liner:

dicts = [dict(zip(k, v)) for k, *zv in [zip(*a)] for v in zv]

Original Answer:

Sometimes a multiline solution can be really straight forward:

# make an iterator for each list
iters = list(map(iter, a))
# pull off first item from each iterator to use as keys        
keys = list(map(next, iters))
# zip the iterators so they are grouped as values, 
# then zip keys and values to make tuples for dict constructor
dicts = [dict(zip(keys, values)) for values in zip(*iters)]

Comments

2

We can use pandas for this, which is more "declarative" in the sense that we specify what we do, and not much how we do that:

import pandas as pd

result = pd.DataFrame({k: v for k, *v in a}).to_dict('records')

for the given a this gives:

>>> pd.DataFrame({k: v for k, *v in a}).to_dict('records')
[{'Name': 'Mary', 'Age': '21', 'Gender': 'F'}, {'Name': 'Tom', 'Age': '23', 'Gender': 'M'}, {'Name': 'John', 'Age': '12', 'Gender': 'M'}]

Comments

2

Kindof ugly oneliner:

first triple the first element of each inner list and zip it with the remaining elements, then zip the unpacked innner tuples to feed it into a dict:

a = [["Name","Mary","Tom","John"],["Age","21","23","12"],["Gender","F","M","M"]]

k = list(dict (o) for o in  zip(*[ zip(l[0:1]*3,l[1:]) for l in a] ))
print(k)

Output:

[{'Gender': 'F', 'Age': '21', 'Name': 'Mary'}, 
 {'Gender': 'M', 'Age': '23', 'Name': 'Tom'}, 
 {'Gender': 'M', 'Age': '12', 'Name': 'John'}]

Comments

2

You could use extended iterable unpacking:

a = [["Name", "Mary", "Tom", "John"], ["Age", "21", "23", "12"], ["Gender", "F", "M", "M"]]
result = [dict(val) for val in zip(*([(header, value) for value in values] for header, *values in a))]
print(result)

Output

[{'Gender': 'F', 'Name': 'Mary', 'Age': '21'}, {'Gender': 'M', 'Name': 'Tom', 'Age': '23'}, {'Gender': 'M', 'Name': 'John', 'Age': '12'}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.