-1

I have the following dict comprehension but I don't know how to convert it back to for loop.

Value = [1,2,3,4,5]
Key = ['a','b','c','a','c']
{k: [Value[i] for i in [j for j, x in enumerate(Key) if x == k]] for k in set(Key)}

I tried:

d1 = {}
for k in set(Key):
    for i in [j for j, x in enumerate(Key) if x == k]:
        d1[k].append(Value[i])   

But this is clearly wrong. Thanks!

Troll
  • 1,895
  • 3
  • 15
  • 34
Iwishworldpeace
  • 478
  • 4
  • 12

3 Answers3

4

I am not sure what Value is previously declared as but the dict comprehension is equivalent to:

d1 = {}
for k in set(Key):
    d1[k] = []

    for i in [j for j, x in enumerate(Key) if x == k]:
        d1[k].append(Value[i])

You need to set d1[k] to an empty list first.

Troll
  • 1,895
  • 3
  • 15
  • 34
3

You just need to create d1[k] as a list.

for k in set(Key):
    d1[k] = []
    ...

Although, the inner list comprehension is redundant: all it really does is rename j to i. You can unwrap it too:

for k in set(Key):
    d1[k] = []
    for i, x in enumerate(Key):
        if x == k:
            d1[k].append(Value[i])

That said, this whole thing is overcomplicated and can be done much more easily with zip:

d1 = {}
for k, v in zip(Key, Value):
    values = d1.setdefault(k, [])
    values.append(v)
print(d1)  # -> {'a': [1, 4], 'b': [2], 'c': [3, 5]}

Although, if Key and Value aren't guaranteed to be the same length, this may fail silently. To avoid that, in Python 3.10+ you could use zip(Key, Value, strict=True), otherwise you could rework it to be for i, k in enumerate(Key) ... values.append(Values[i]).

Note: In Python 3.7+, this solution preserves insertion order where yours doesn't due to the set conversion.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
1

Consider the following code in the question:

{k: [Value[i] for i in [j for j, x in enumerate(Key) if x == k]] for k in set(Key)}

It might be a pretty great one-liner, but it's not immediately obvious to anyone what it does. In fact I spent a bit of time puzzling out how it works, and I still don't fully understand it yet.

In this case, I would suggest simplifying it, perhaps by splitting it over a few extra lines, just so that it's clearer for others and also for yourself what is going on. For example, consider the following example with defaultdict, which is a subclass of dict:

my_dict = defaultdict(list)
for k, v in zip(Key, Value):
    my_dict[k].append(v)

Result of my_dict, which again contains the same contents:

defaultdict(<class 'list'>, {'a': [1, 4], 'b': [2], 'c': [3, 5]})
rv.kvetch
  • 9,940
  • 3
  • 24
  • 53