Nanda
Nanda

Reputation: 1

Python: Using dict as accumulator

I am trying to get the counts of each word in a text file with the below code.

def count_words(file_name):
    with open(file_name, 'r') as f: return reduce(lambda acc, x: acc.get(x, 0) + 1,   sum([line.split() for line in f], []), dict())

but I get the error

File "C:\Python27\abc.py", line 173, in count_words
with open(file_name, 'r') as f: return reduce(lambda acc, x: acc.get(x, 0) + 1, sum([line.split() for line in f], []), dict())
File "C:\Python27\abc.py", line 173, in <lambda>
with open(file_name, 'r') as f: return reduce(lambda acc, x: acc.get(x, 0) + 1, sum([line.split() for line in f], []), dict())
AttributeError: 'int' object has no attribute 'get'

I am not able to understand the error message here. Why does it complain that 'int' has no attribute even when I passed a dict as accumulator?

Upvotes: 0

Views: 1891

Answers (3)

sloth
sloth

Reputation: 101072

The problem is that your lambda function returns an int, but not a dict.

So, even if you use a dict as seed, when your lambda function is called the second time, acc will be the result of acc.get(x, 0) + 1 from the first call, and it's an int and not a dict.

Upvotes: 2

user4482921
user4482921

Reputation:

So if you are looking for a one-liner, I almost have a one-liner in the spirit of what you were trying to do with get.

>>> words = """One flew over the ocean
... One flew over the sea
... My Bonnie loves pizza
... but she doesn't love me"""
>>>
>>> f = open('foo.txt', 'w')
>>> f.writelines(words)
>>> f.close()

The "one-liner" (two-liner actually)

>>> word_count = {}
>>> with open('foo.txt', 'r') as f:
...     _ = [word_count.update({word:word_count.get(word,0)+1}) for word in f.read().split()]
... 

Result:

>>> word_count
{'but': 1, 'One': 2, 'the': 2, 'she': 1, 'over': 2, 'love': 1, 'loves': 1, 'ocean': 1, "doesn't": 1, 'pizza': 1, 'My': 1, 'me': 1, 'flew': 2, 'sea': 1, 'Bonnie': 1}

I imagine there's something you could do with a dict comprehension, but I couldn't see how to use get in that case.

The f.read().split() gives you a nice list of words to work with, however, and should be easier than trying to get words out of a list of lines. It's a better approach unless you have a huge file.

Upvotes: 1

zhangxaochen
zhangxaochen

Reputation: 34017

You can use collections.Counter to count the words:

In [692]: t='I am trying to get the counts of each word in a text file with the below code'
In [693]: from collections import Counter

In [694]: Counter(t.split())
Out[694]: Counter({'the': 2, 'a': 1, 'code': 1, 'word': 1, 'get': 1, 'I': 1, 'of': 1, 'in': 1, 'am': 1, 'to': 1, 'below': 1, 'text': 1, 'file': 1, 'each': 1, 'trying': 1, 'with': 1, 'counts': 1})

In [695]: c=Counter(t.split())

In [696]: c['the']
Out[696]: 2

Upvotes: 3

Related Questions