0

I'm trying to simplify the following code using list/dict comprehension, in which I want to build a dictionary of lists from a list.

In this example, I take the mod (or any other function) of each item as the key. If the key doesn't exist in the dictionary, a new list is created and the item is appended to the list, otherwise the item is directly appended.

def get_key(val):
    return val % 3 # Can be something else, it doesn't matter


dict = {}
data = [i for i in range(10)]
for item in data:
    key = get_key(item)
    if key in dict:
        dict[key].append(item)
    else:
        dict[key] = [item]
print(dict)

Expected output

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

To simplify the above code, I have tried this ugly approach:

for item in data:
    key = get_key(item)
    dict[key] = [item] if key not in dict else (dict[key], dict[key].append(item))[0]

However, how to achieve the same thing without the for-loop, using list/dict comprehension as a single expression?

I could think of something like this, but it's not able to append value into a pre-existing list.

{get_key(item):[item] for item in data}

Related posts:

coderoftheday
  • 1,987
  • 4
  • 7
  • 21
PIG208
  • 2,060
  • 2
  • 10
  • 25

4 Answers4

1

You are close. below is my approach for using dict comprehension

data = list(range(0,10))
mod= 3
{i:data[i::mod] for i in range(mod)}

Out

{0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}
Equinox
  • 6,483
  • 3
  • 23
  • 32
  • Thank you. This method works well for data of a list of increasing consecutive integers in case the key is determined by mod. But it can't be generalized to other cases when the key is determined by other rules. I have updated my question to make it clearer. – PIG208 Dec 11 '20 at 12:32
1

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)]}
coderoftheday
  • 1,987
  • 4
  • 7
  • 21
0

You don't really need list/dict comprehension here. Just use a normal loop with defaultdict:

out = collections.defaultdict(list)
for i in range(10):
    out[i % 3].append(i)
VisioN
  • 143,310
  • 32
  • 282
  • 281
  • Thank you for your answer. Practically it works, but I'm looking for a single expression solution using list/dict comprehension. – PIG208 Dec 11 '20 at 11:39
0

Try default dict,

from collections import defaultdict

d = defaultdict(list)
for item in range(10): 
    d[item % 3].append(item)
pjk
  • 547
  • 3
  • 14