0

I'm a beginner in python and I want to use comprehension to create a dictionary. Let's say I have the below two list and want to convert them to a dictionary like {'Key 1':['c','d'], 'Key 2':['a','f'], 'Key 3':['b','e']}. I can only think of the code below and I don't know how to change the value of the key and the filter using comprehension. How should I change my code?

value = ['a','b','c','d','e','f']
key = [2, 3, 1, 1, 3, 2]
{"Key 1" : [value for key,value in list(zip(key,value)) if key==1]}
1
  • I don't think there's an asymptotically efficient comprehension solution. Commented Oct 31, 2020 at 10:03

4 Answers 4

3

This should do it:

value = ['a','b','c','d','e','f']
key = [2, 3, 1, 1, 3, 2]

answer = {}
for k, v in zip(key, value):
    if k in answer:
        answer[k].append(v)
    else:
        answer[k] = [v]

print(answer)
{2: ['a', 'f'], 3: ['b', 'e'], 1: ['c', 'd']}

EDIT: oops, jumped the gun. Apologies.

Here's the comprehension version, but it's not very efficient:

{
    k: [v for i, v in enumerate(value) if key[i] == k]
    for k in set(key)
}

EDIT 2:

Here's an one that has better complexity:

import pandas as pd
series = pd.Series(key)
{
    k: [value[i] for i in indices]
    for k, indices in series.groupby(series).groups.items()
}
Sign up to request clarification or add additional context in comments.

4 Comments

The OP wants to use comprehension, not a for loop.
This ain't list comprehension, though
The comprehension solution looks like O(m*n) where m=len(set(key)) and n=len(key).
The first example can be simplified: result = {digit: [] for digit in digits}; "or result=defaultdict(list)"; for digit, letter in zip(digits, letters): result[digit].append(letter)
1

You could do it with dictionary comprehension and list comprehension:

{f"Key {k}" : [value for key,value in zip(key,value) if key == k] for k in key}

Your lists would yield the following:

{'Key 2': ['a', 'f'], 'Key 3': ['b', 'e'], 'Key 1': ['c', 'd']}

As requested.

8 Comments

no need to create the values list for the same key several times (that is why set() is used in @anthony-khong's answer
thanks. this will work but is there a way to start the dictionary from key 1?
@tequila, dictionaries are unordered, if you'd like it ordered, you should use an OrderedDict.
@anthony-khong: dicts are ordered since Python 3.7 officially (before that Pypy, CPython 3.6+ use ordered dict implementations).
@jfs true if you're only doing looping, but you still shouldn't rely on dict's orderedness, because it's an implementation detail. You can get nasty comparison surprises. See: stackoverflow.com/a/50872567/3546333
|
1

use dict setdefault

value = ['a', 'b', 'c', 'd', 'e', 'f']
key = [2, 3, 1, 1, 3, 2]
d = {}
{d.setdefault(f'Key {k}', []).append(v) for k, v in zip(key, value)}
print(d)

output

{'Key 2': ['a', 'f'], 'Key 3': ['b', 'e'], 'Key 1': ['c', 'd']}

1 Comment

note: there is no dict comprehension in the answer.
1

Usually, it is written as an explicit loop (O(n) solution):

>>> letters = 'abcdef'
>>> digits = [2, 3, 1, 1, 3, 2]
>>> from collections import defaultdict
>>> result = defaultdict(list)  # digit -> letters
>>> for digit, letter in zip(digits, letters):
...     result[digit].append(letter)
>>> result
defaultdict(<class 'list'>, {2: ['a', 'f'], 3: ['b', 'e'], 1: ['c', 'd']})

Nested comprehensions (O(n n) solution) like in other answers:

>>> {
...     digit: [letter for d, letter in zip(digits, letters) if digit == d]
...     for digit in set(digits)
... }
{1: ['c', 'd'], 2: ['a', 'f'], 3: ['b', 'e']}

If you need to write it as a single dict comprehension, itertools.groupby could be used (O(n log n) solution):

>>> from itertools import groupby
>>> {
...     digit: [letter for _, letter in group]
...     for digit, group in groupby(
...         sorted(zip(digits, letters), key=lambda x: x[0]), 
...         key=lambda x: x[0]
...     )
... }

Comments

Your Answer

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