0

I am starting to use list comprehensions and i am a bit lost in the syntax, how can i translate this to dict comprehensions:

dict_users = Counter()
largo = len(wut)
for user in wut:
    count = 0
    for line in lines:
        if user in line:
            count += 1
    dict_users[user] = count

i have tried different variations but i keep getting it wrong.

dict_users ={user: count for user in wut count = 0 for line in lines if user in lines}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
NachoMiguel
  • 983
  • 2
  • 15
  • 29
  • I'm not sure if using a dict comprehension is the best approach for this. – Christian Tapia Oct 07 '15 at 14:39
  • @Christian i was just trying to improve the code, but if u guys say is not worthy then i will leave it as it is – NachoMiguel Oct 07 '15 at 14:41
  • I said I'm not sure. Not an expert in dict comprehension. And I don't know why did you get the downvote. It looks like a fair attempt to solve it. – Christian Tapia Oct 07 '15 at 14:42
  • Probably downvoted because your code and question does not provide enough information to allow someone else to easily debug. For example you are using variables like `lines` and `wut` without any context as to how these variables have been assigned/instantiated. – David Zemens Oct 07 '15 at 14:54
  • @DavidZemens to be fair `Counter` (from the `collections` module) is part of the standard library. Examples of `lines` and `wut` (wut?!) would have been useful, I agree. – jonrsharpe Oct 07 '15 at 14:56
  • @DavidZemens i agree with all u said, i will try to be more precise from now on – NachoMiguel Oct 07 '15 at 14:59

3 Answers3

4

You can't assign (count = 0 or count += 1) in a generator expression/list or dict comprehension, you need to use sum for this kind of thing instead. I think what you wanted is:

dict_users = {user: sum(user in line for line in lines) for user in wut }

Note that this uses the fact that True ('f' in 'foo') and False ('f' in 'bar') evaluate to 1 and 0 respectively when summed, as the booleans are integer subclasses. A simple example:

>>> lines = ['foo', 'bar', 'baz']
>>> users = ['ba', 'f']
>>> {user: sum(user in line for line in lines) for user in users}
{'ba': 2, 'f': 1}

But this is arguably less readable than the nested for loops you have now.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
2

Counter already counts the items for you; you just need an appropriate sequence of lines to pass as the argument.

dictUsers = Counter(line for user in wut for line in lines if user in line)

The for clauses in the generator expression appear in the same order as the equivalent nested for loop.

chepner
  • 497,756
  • 71
  • 530
  • 681
1

Actually I recently read a blog post that explained nested comprehensions rather well, though I don't remember the link. To expand on jonrsharpe's answers:

for x in list_of_tuples:
    for y in x:
        do(y)

Becomes:

[do(y) for x in list_of_tuples for y in x]

So essentially you're hitting backspace until all your for's are on one line, delete colons, and then just moving final function to the front.

Keep in mind that you can't have any assignments, only for and the final action.

CAN'T MAKE A COMPREHENSION:

for x in range(10):
    x = range(x)
    for y in x:
        do(y)

CAN COMPREHEND:

for x in range(10):
    for y in range(x):
        do(y)
postelrich
  • 3,274
  • 5
  • 38
  • 65