count number of n grams in text

import re
N = 2
list = []
counts = dict()
ngarms = []
with open('man.txt','r',encoding='cp1251') as f:
        for sent in f:
            sent = sent.lower()
            sent = re.sub('[0-9A-z\'\"`\|\/\+\#\,\)\(\?\!\B\-\:\=\;\.\«\»\-\—]', '', sent)
            sent = sent.split()
            for word in sent:
                word = word.lower()
                list.append(word)


grams = [list[i:i+N] for i in range(len(list)-N)]
    for gram in grams:
        if gram not in counts:
           counts[word] = 1
        else:
           counts[word] += 1

I try to count nubber of each Ngram in the text, but when do it using method with dictionary I get error: if gram not in counts: TypeError: unhashable type: 'list'

man.txt looks like this:

Ми набрали стільки різної музики, що слухати її вже ніхто не хотів. Якісь — Сільві, це зміна тиску, — кажу я їй — Двірники тут не допоможуть. Джаз, до речі, теж. Так уже складається, що я маю пити сам. Між Сільві й Ґашпером існує джентльменська угода, що десь там після умовного перетину австрійсько-німецького кордону він її підмінить за кермом, а на автобані пити він все ж таки не наважується, тож я собі відкриваю чергову банку, зідравши з неї чеку, й намагаюсь підтримувати розмову. Загалом, перша сотня кілометрів мені знайома, торік я їздив тут автостопом, мене тоді підібрав якийсь божевільний панк, який весь час нервово пив спрайт, його сушило, схоже він був з обкурки, але гнав таки на Захід, бо мусив, уже не знаю, що там у нього було, може, мама чекала, однак вигляд у нього був нещасний. Коли я дістав з наплічника пляшку води, він спитався, чи це не водка бува, у вас же там, в Росії, всі п’ють водку, ні, не водка, кажу, і він весело розсміявся. Тупий якийсь панк трапився. Зараз я намагаюсь переповісти все це Сільві, виловлюючи її увагу з атональних джазових ям і порожнин, Сільві погоджується — так, справді тупий панк, що тут скажеш, розмова не в’яжеться, і я відкриваю наступну банку, все одно поки що нічого цікавого — голі пасовища, безлисті лісосмуги, печальна березнева Австро-Угорщина, мабуть, саме такою її і запам’ятали російські піхотинці навесні 45-го, депресивний доволі ландшафт, ось вони і хуячили наліво і направо елітні дивізії нещасних націонал-соціалістів. У цей час касета добігає кінця і тут таки починає розкручуватись у зворотньому напрямку, новий джаз знову бере за горло, і я заходжуся шукати під кріслами забутого і присипаного фісташками старого-доброго Лу Ріда. «Джаз — музика для товстих», — кажу я Сільві й міняю касети. Десь уже на німецькій території нам трапилася військова колона, що розтяглась на добрих два десятки кілометрів.

It is a book

How can I fix this?

Upvotes: 0

Views: 357

Answers (2)

Anand S Kumar
Anand S Kumar

Reputation: 90989

Assuming all the indentation mistakes in your code are actually only copy/paste mistakes, the issue is that grams is a list of list, which contains 2 elements each in the inner list.

When you do - for gram in grams: , you are getting the inner list in gram variable which is a list, then you are trying to check whether the gram variable is a key in the counts dictionary.

This leads to error, because we cannot use list as keys for dictionary , since they are not hashable.

I am not clearly sure what the complete ask is, but an example of how to fix the issue would be to iterate through each gram again and check if the elements inside the inner list are present in the counts dictionary.

Example -

for gram in grams:
    for g in gram:
        if g not in counts:
            counts[word] = 1
        else:
            counts[word] += 1

But I don't think using word over there is correct, since it would most probably use the last value that of word from within the with block. Maybe you need to use g variable instead as I used above???

Also, its advised that you do not use list as the name of a variable since it overwrites the built-in list() function.


Since the ask is that the OP wants to count the number of times each sequence of words come in the text. You can do it by creating grams list as a list of all sequences by using join , for example and then using his own example -

grams = [' '.join(list[i:i+N]) for i in range(len(list)-N)] for gram in grams: if gram not in counts: counts[word] = 1 else: counts[word] += 1

Upvotes: 1

jhoepken
jhoepken

Reputation: 1858

Assuming that list contains each word of the file as a list element and you are looking for the word ngram, just test each list element for equality:

ngrams = [word for word in list if word == "ngram"]
print len(ngrams)

Upvotes: 0

Related Questions