Create a Dictionary With Comprehension

Create a dictionary with comprehension

Use a dict comprehension (Python 2.7 and later):

{key: value for (key, value) in iterable}

Alternatively for simpler cases or earlier version of Python, use the dict constructor, e.g.:

pairs = [('a', 1), ('b', 2)]
dict(pairs) #=> {'a': 1, 'b': 2}
dict([(k, v+1) for k, v in pairs]) #=> {'a': 2, 'b': 3}

Given separate arrays of keys and values, use the dict constructor with zip:

keys = ['a', 'b']
values = [1, 2]
dict(zip(keys, values)) #=> {'a': 1, 'b': 2}
2) "zip'ped" from two separate iterables of keys/vals
dict(zip(list_of_keys, list_of_values))

How to create a dictionary of dictionaries using dict comprehension?

You got your nesting mixed up. The following works:

{name: {col: int(value) for col, value in zip(grades_list[0][1:], row)}
for name, *row in grades_list[1:]}

The for name, *row in ... loop takes each row, and extracts just the first value into name, the remainder into row (the * tells Python to take the remainder). This lets you then use the row together with the column names from the first row to create the nested dictionaries.

It is often easier to see what a comprehension does by using regular loops. Your code does this:

grade_dicts = {}
for y in grades_lists[0][1:]:
for x in grades_lists[1:]:
for z in x[1:]:
grade_dicts[x[0]] = {y:z}

That's way too many loops, and you end up setting a value for x[0] several times; len(x[1:]) times in fact. Only the last {y: z} dictionary remains.

My version does this:

grade_dicts = {}
for name, *row in grades_list[1:]:
inner = {}
for col, value in zip(grades_list[0][1:], row):
inner[col] = int(value)
grade_dicts[name] = inner

That's just two loops, where the inner produces a separate dictionary for each column. I used zip() to pair up the labels and the values.

Self-referential dictionary comprehension

In general you won't be able to reference the dictionary itself in the comprehension, because the name won't get assigned to the resulting dictionary until the comprehension is completed, so you'll have to settle for predefining the dictionary* and utilize mutating methods of the existing dictionary.

Since you're iterating over the input list, you'll need to update the existing dictionary with the new values whenever you come across the key. And as you can't use an assignment in the dictionary comprehension, you'll want to use the dict.update() method (or __setitem__ or setdefault). That method always returns None, so you can utilize that to achieve the desired side effect in a number of different places inside the dictionary comprehension.

In particular, any filtering condition clause will be executed, so you can use that. Alternatively, expr or value will evaluate the expression, which will always return None, and since that's falsey the whole expression evaluates to value, so you can place that expression in the key or value. That gives us the following possibilities:

With the side effect in the filter clause:

d = {}
d = {k: d[k] for k, *vals in x if d.update({k: d.get(k, []) + vals}) is None}

With the side effect in a expr or key expression:

d = {}
d = {d.update({k: d.get(k, []) + vals}) or k: d[k] for k, *vals in x}

With the side effect in a expr or value expression:

d = {}
d = {k: d.update({k: d.get(k, []) + vals}) or d[k] for k, *vals in x}

* Using assignment expressions (Python 3.8+), you can predefine the dictionary inside the comprehension itself with this abomination:

d = {k: d.update({k: d.get(k, []) + vals}) or d[k] for i, (k, *vals) in enumerate(x) if i or not (d := {})}

This uses enumerate() to detect when you're on the first iteration, in which case an assignment expression can construct the dictionary that is used in the rest of the comprehension. After the first iteration, the assignment expression is not evaluated again so d doesn't get reassigned in the course of the evaluation.


Note: Obviously, all of the methods shown in this answer are terrible. Side-effects inside comprehensions are unnecessary, unexpected, confusing, and in one word, silly. Do not use this code. But it is fun to see what's possible!

Building a dictionary with lists as values using list comprehension

Create a list of list of the values, with the first element of each sublist being the key which is [n] +, then use that to create a dictionary.

m = [[n] + [i[1] for i in [(x%3,x) for x in range(10)]if i[0] == n] for n in range(3)]

dictt = {i[0]:i[1:] for i in m}
print(dictt)

>>> {0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}

All on one line

dictt = {i[0]:i[1:] for i in [[n] + [i[1] for i in [(x%3,x) for x in range(10)]if i[0] == n] for n in range(3)]}

Comprehension list of nested dictionary to get values but got keys

You could use this. I personnally try to avoid nested list comprehension as they are hard to read and debug.

[[x['category'], x['user']['displayName']] for nest_list in the_list for x in nest_list["values"] ]

Output:

[['Secretary', 'Anna'], ['Manager', 'Bobby'], ['Secretary', 'Clarissa Claire']]

EDIT:
A version that doesn't have a nested comprehension list. When doing it I realised that there was one more level than I realised that makes this version a bit long. So in the end I'm not sure which one I would use in prod.

result = []
dict_list = [nest_list["values"] for nest_list in the_list]
for elt in dict_list:
for d in elt:
result.append([d['category'], d['user']['displayName']])

Dictionary comprehensions using two different sources for keys and values

Zip the two sources together:

pssmDict = {key: value for key, value in zip(range(0, len(pssmList)), pssmList)}

However, in this case, you can simply use enumerate to generate the keys.

pssmDict = {key: value for key, value in enumerate(pssmList)}

The results of zip and enumerate are suitable for passing directly to dict; no need for a dictionary comprehension:

pssmDict = dict(enumerate(pssmList))


Related Topics



Leave a reply



Submit