ywan
ywan

Reputation: 137

How to refactor my for loop as python dictionary comprehension?

I am using Python 3.6. I wrote following code, it's a for loop:

Edit: I made a mistake when I wrote var l down, so I re-type it here. Thanks for @Ender Look !!

l = [['a','1'], ['a','2'], ['a','3']]
d = {}
for i in l:
    d[i[0]] = d.get(i[0], '') + '\t' + i[1]
print (d)

So, the result is what I want: {'a': '\t1\t2\t3'}

Then I refactor above code as comprehension:

dict2 = {} dict2 = {i[0]: dict2.get(i[0], '') + '\t' + i[1] for i in l} print(dict2)

I though they should return same output. But the dict2 is:

{'a': '\t3'}

I want to know what's the matter with my dict comprehension? Thanks a lot!

Upvotes: 3

Views: 218

Answers (3)

gilch
gilch

Reputation: 11641

Yes, you can do it as a single dict comprehension.

{k: v
 for d in [{}]
 for k, v in [d.__setitem__(k, d.get(k, '') + '\t' + v) or d 
              for k, v in [['a','1'], ['a','2'], ['a','3']]][-1].items()}

You shouldn't.

Note how we had to create a reference to an inner dict d anyway, since your algorithm has to look things up in the dict as it's being constructed. What is the outer comprehension even for? And we're throwing away all but the last element of the inner list comp.

It's much clearer to use a normal for loop like this,

d = {}
for k, v in [['a','1'], ['a','2'], ['a','3']]:
    d[k] = d.get(k, '') + '\t' + v

Use the right tool for the job.

Upvotes: 0

idjaw
idjaw

Reputation: 26570

You don't necessarily need to use a comprehension here. You can make use of defaultdict from collections:

>>> from collections import defaultdict
>>> d = defaultdict(str)
>>> for li in l:
...  d[li[0]] += f'\t{li[1]}'
...
>>> d
defaultdict(<class 'str'>, {'a': '\t1\t2'})

Upvotes: 5

Ender Look
Ender Look

Reputation: 2391

Your dictionary comprehension doesn't work because it's use .get on itself.

dict2 = {i[0]: dict2.get(i[0], '') + '\t' + i[1] for i in l}

Until the end of the whole dictionary comprehension, this new dictionary isn't assigned to your actual dict2 variable. So all the times your comprehension tries to retrieve the value from dict2.get(...) it always executes that function from the empty dictionary dict2 = {}.

Sadly, I don't know (and I don't think it exists) a way to use .get on a dictionary comprehension about itself, because the variable dict2 isn't updated on "real time" (it wait until the end the comprehension). Or at least that I have understood, my humble knowledge isn't perfect.

Upvotes: 3

Related Questions