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]}

4 Answers4

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()
}
anthony-khong
  • 141
  • 2
  • 4
  • 1
    The OP wants to use comprehension, not a for loop. – Advay168 Oct 31 '20 at 09:56
  • 1
    This ain't list comprehension, though – rjg Oct 31 '20 at 09:56
  • 2
    The comprehension solution looks like `O(m*n)` where `m=len(set(key))` and `n=len(key)`. – bereal Oct 31 '20 at 10:02
  • 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)` – jfs Oct 31 '20 at 10:11
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.

MrMister
  • 2,456
  • 21
  • 31
  • 1
    no need to create the values list for the same key several times (that is why `set()` is used in [@anthony-khong's answer](https://stackoverflow.com/a/64620470/4279) – jfs Oct 31 '20 at 10:15
  • 1
    thanks. this will work but is there a way to start the dictionary from key 1? –  Oct 31 '20 at 10:25
  • @tequila, dictionaries are unordered, if you'd like it ordered, you should use an OrderedDict. – anthony-khong Oct 31 '20 at 10:29
  • @anthony-khong: dicts are ordered since Python 3.7 officially (before that Pypy, CPython 3.6+ use ordered dict implementations). – jfs Oct 31 '20 at 10:40
  • @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: https://stackoverflow.com/a/50872567/3546333 – anthony-khong Oct 31 '20 at 11:12
  • @anthony-khong the insertion order is guaranteed by the language no matter its implementation. The statement: « dicts are unordered » is wrong. You can rely on the order. For example, 2,3,1 order is guaranteed for the code in the answer (2 key is inserted before 3, before 1). To get 1,2,3 order, `sorted(key)` may be used. – jfs Oct 31 '20 at 13:21
  • @tequila as @jfs mentioned, to have the output as `{'Key 1': ['c', 'd'], 'Key 2': ['a', 'f'], 'Key 3': ['b', 'e']}` you can use the following amendment: `{f"Key {k}" : [value for key,value in zip(key,value) if key == k] for k in sorted(key)}` – MrMister Oct 31 '20 at 16:59
  • @jfs, I looked this up, and I believe you're right, and I was wrong. Sorry about that. From the official docs (https://docs.python.org/3/library/stdtypes.html?highlight=dict#mapping-types-dict): "Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was an implementation detail of CPython from 3.6." – anthony-khong Nov 01 '20 at 11:53
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']}
balderman
  • 22,927
  • 7
  • 34
  • 52
0

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]
...     )
... }
jfs
  • 399,953
  • 195
  • 994
  • 1,670