Marko Markusevic
Marko Markusevic

Reputation: 17

python counter function unhashable type: 'list'

I want to use Counter function in my code, but im getting unhashable type error.

lexicalClass = file.readlines()


for lex in lexicalClass:
  newList = re.findall('\S+', lex)
  for element in newList:
      if len(re.findall('[a-z]+|[0-9]+', element)):
        identifiers.append(re.findall('[a-z]+|[0-9]+', element))

I put in my txt file some strings, and im putting strings into "identifiers" list. And now, when i try to use print(Counter(identifiers)) im getting this error:

Traceback (most recent call last):

File "C:\Users\jule\.spyder-py3\temp.py", line 93, in <module>
print(Counter(identifiers))

File "C:\Users\jule\anaconda3\lib\collections\__init__.py", line 552, in __init__
self.update(iterable, **kwds)

File "C:\Users\jule\anaconda3\lib\collections\__init__.py", line 637, in update
_count_elements(self, iterable)

TypeError: unhashable type: 'list'

Upvotes: 0

Views: 1232

Answers (2)

dawg
dawg

Reputation: 103864

You can use a Counter on list of hashable items:

>>> Counter(['a','b','c','a'])
Counter({'a': 2, 'b': 1, 'c': 1})

You cannot use a Counter on a list of unhashable items (and lists, being mutable, are not hashable):

>>> Counter([['a','b'],['c','a']])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/[email protected]/3.9.1_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py", line 593, in __init__
    self.update(iterable, **kwds)
  File "/usr/local/Cellar/[email protected]/3.9.1_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py", line 679, in update
    _count_elements(self, iterable)
TypeError: unhashable type: 'list'

Since re.findall produces a list of tuples or a list of strings, you need to use the Counter directly on that list. If you use .append with the list result from re.findall you end up with a list of lists and you will see the error you are seeing.

Luckily, you can update a Counter directly. You can do something like:

>>> txt='''\
... line 1
... Line 2
... LINE 3'''
>>> lines=Counter()
>>> lines.update(re.findall(r'^l', txt, flags=re.M))
>>> lines.update(re.findall(r'^L', txt, flags=re.M))
>>> lines.update(re.findall(r'^LINE', txt, flags=re.M))
>>> lines
Counter({'L': 2, 'l': 1, 'LINE': 1})

Upvotes: 0

Pierre-Loic
Pierre-Loic

Reputation: 1564

All the objects in a Counter need to be hashable :

A Counter is a dict subclass for counting hashable objects

The function re.findall() gives you a list of strings. You can update your code like that :

identifiers.extend(re.findall('[a-z]+|[0-9]+', element))

or

identifiers += re.findall('[a-z]+|[0-9]+', element)

Upvotes: 1

Related Questions