Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert forloop to list comprehension

I am trying to convert the following to list comprehension but struggling:

lorem_ipsum = """Lorem ipsum dolor sit amet, consectetur adipiscing elit."""

def word_count2(str):
    counts = dict()
    words = str.split() 

    for word in words:
        if word in counts:
            counts[word] += 1
        else:
            counts[word] = 1

    return counts

print(word_count2(lorem_ipsum))

So far I have tried a few variations on this:-

aString = lorem_ipsum

counts = dict()
words = aString.split

[counts[word] += 1 if word in counts else counts[word] = 1 for word in words]

Unfortunately, it has been some hours now but nothing I have tried seems to work

like image 538
JasonExcel Avatar asked Apr 16 '26 03:04

JasonExcel


2 Answers

Warning! You are trying to use a side effect inside of a list comprehension:

[counts[word] += 1 if word in counts else counts[word] = 1 for word in words]

tries to update counts for every word. List comprehension are not meant to be used like that.

The class itertools.Counter is designed to solve your problem, and you can use a dict comprehension that counts every element (see other answers). But the dict comprehension has a O(n^2) complexity: for every element of the list, read the full list to find that element. If you want something functional, use a fold:

>>> lorem_ipsum = """Lorem ipsum dolor sit amet, consectetur adipiscing elit."""
>>> import functools
>>> functools.reduce(lambda d, w: {**d, w: d.get(w, 0)+1}, lorem_ipsum.split(), {})
{'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1}

For every word w, we udpate the current dictionary: d[w] is replaced by d[w]+1 (or 0+1 if w was not in d).

That gives a hint on how you could have written your list comprehension:

>>> counts = {}
>>> [counts.update({word: counts.get(word, 0) + 1}) for word in lorem_ipsum.split()]
[None, None, None, None, None, None, None, None]
>>> counts
{'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1}

As you see, [None, None, None, None, None, None, None, None] is the real return value of the list comprehension. The dictionary count was updated but do not do this!. Do not use a list comprehension unless you use the result.

like image 169
jferard Avatar answered Apr 18 '26 17:04

jferard


Comprehensions aren't the right tool for this job. A collections.Counter is:

>>> from collections import Counter
>>> counts = Counter(lorem_ipsum.split())
>>> print(counts)
Counter({'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1})
>>> counts['Lorem']
1
>>> counts['foo']
0
like image 43
Dennis Avatar answered Apr 18 '26 16:04

Dennis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!