Home > Net >  What is the for loop for this dictionary comprehension?
What is the for loop for this dictionary comprehension?

Time:10-30

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!

CodePudding user response:

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.

CodePudding user response:

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.

CodePudding user response:

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]})
  • Related