2016-09-12 21 views
7

У меня есть файл, состоящий из слов, по одному слову на каждой строке. Файл выглядит так:ТипError: str объект не является итератором

aaa 
bob 
fff 
err 
ddd 
fff 
err 

Я хочу посчитать частоту пары слов, которые происходят один за другим.

Например,

aaa,bob: 1 
bob,fff:1 
fff,err:2 

и так далее. Я попытался это

f=open(file,'r') 
content=f.readlines() 
f.close() 
dic={} 
it=iter(content) 
for line in content: 
    print line, next(line); 
    dic.update({[line,next(line)]: 1}) 

я получил ошибку:

TypeError: str object is not an iterator 

Затем я попытался с помощью итератора:

it=iter(content) 
for x in it: 
    print x, next(x); 

снова получил ту же ошибку. Пожалуйста, помогите!

+3

Что вы думаете о 'следующей (вещи)' делает? Это не означает «вещь, которая приходит после« вещи ». – user2357112

+0

Кроме того, одним из решений является: 'pprint.pprint (collections.Counter (zip (content [0:], content [1:])). Most_common())' –

+0

@ user2357112: То, что я думал дальше! Что делать дальше? В документе python говорится: «Извлеките следующий элемент из итератора, вызвав его метод next(). Если задано значение по умолчанию, оно возвращается, если итератор исчерпан, иначе StopIteration будет поднят. – rowana

ответ

6

Вам просто нужно отслеживать предыдущую строку, файл-объект возвращает свой собственный итератор, поэтому вам не нужен итератор или readlines вообще, вызовите следующий один раз в самом начале, чтобы создать переменную пред то просто постоянно обновлять пред в петле:

from collections import defaultdict 

d = defaultdict(int) 

with open("in.txt") as f: 
    prev = next(f).strip() 
    for line in map(str.strip,f): # python2 use itertools.imap 
     d[prev, line] += 1 
     prev = line 

Который даст вам:

defaultdict(<type 'int'>, {('aaa', 'bob'): 1, ('fff', 'err'): 2, ('err', 'ddd'): 1, ('bob', 'fff'): 1, ('ddd', 'fff'): 1}) 
+1

Это отличный пример использования итератора. Подумайте о следующем: '[] .pop()': он возвращает следующее значение, но также удаляет его из итератора. Одно из преимуществ этого - псевдо-сокращение, как это: получить начальное значение, а затем перебрать остальные. –

-1

Ваша ценность x содержит строку 'ddd/ccc/etc'. он не следующий. next() принадлежит итератору, и он использовал для получения следующего элемента из итератора. Правильный способ назвать это it.next()

it=iter(content) 
for x in it: 
    print x, it.next(); 

Но вы получите исключение после того, как вы закончите потреблять все элементы в итераторе. Итак, вам нужно поймать исключение StopIteration.

for x in it: 
    try: 
     line, next_line = x, it.next() 
     # do your count logic overhere 
    except StopIteration: 
     break 

dic.update({[line,next_line]: 1}) не работает. Вы пропустите возможные комбинации.

+1

Не должно быть 'next (it)'? –

+0

@PavelGurkov it.next() работает также. – levi

+0

@levi, Спасибо. Он отлично работал. К сожалению, у меня недостаточно кредитов для голосования. Когда я это сделаю, я сделаю это! – rowana

3

line, как и все strs, является ITER состояние, что означает, что имеет __iter__ метод. Но next работает с iter аторы, у которых есть метод __next__ (в Python 2 это метод next). Когда интерпретатор выполняет next(line), он пытается вызвать line.__next__. Поскольку line не имеет метода __next__, он поднимает TypeError: str object is not an iterator.

Поскольку line является ИТЭРОМ состояния и имеет __iter__ метод, мы можем установить it = iter(line). it является итератором атор с __next__, а next(it) возвращает следующий символ в line. Но вы ищете следующую строку в файл, так что попробовать что-то вроде:

from collections import defaultdict 

dic = defaultdict(int) 
with open('file.txt') as f: 
    content = f.readlines() 
    for i in range(len(content) - 1): 
     key = content[i].rstrip() + ',' + content[i+1].rstrip() 
     dic[key] += 1 

for k,v in dic.items(): 
    print(k,':',v) 

Выход (file.txt как в OP)

err,ddd : 1 
ddd,fff : 1 
aaa,bob : 1 
fff,err : 2 
bob,fff : 1 
0

Как другие упомянули, вы можете Не используйте next на строке, которая является строкой.Вы можете использовать itertools.tee, чтобы создать два независимых итератор из вашего файлового объекта, а затем использовать collections.Counter и zip создать объект счетчика из пар линий

from itertools import tee 
from collections import Counter 
with open('test.txt') as f: 
    # f = (line.rstrip() for line in f) # if you don't want the trailing new lines 
    f, ne = tee(f) 
    next(ne) 
    print(Counter(zip(f, ne))) 

к сведению, что поскольку объект файл содержит строки с новой строки в их конец, если вы не хотите, чтобы вы могли линять линии.

3
from collections import Counter 
with open(file, 'r') as f: 
    content = f.readlines() 
result = Counter((a, b) for a, b in zip(content[0:-1], content[1:])) 

Это будет словарь, ключи которого являются парами линий (в порядке) и значениями которых является количество раз, когда эта пара произошла.

1

Как другие говорили, линии является строкой и, следовательно, не может быть использован со следующим() методом . Также вы не можете использовать список в качестве ключа для словаря, потому что они хешируются. Вместо этого вы можете использовать кортеж. Простое решение:

f=open(file,'r') 
content=f.readlines() 
f.close() 

dic={} 

for i in range(len(content)-1): 
    print(content[i], content[i+1]) 
    try: 
     dic[(content[i], content[i+1])] += 1 
    except KeyError: 
     dic[(content[i], content[i+1])] = 1 

Также обратите внимание, что при использовании readlines() вы также сохранить «\ п» каждой строки. Вы можете лишить его первый:

content = [] 
    with open(file,'r') as f: 
     for line in f: 
      content.append(line.strip('\n')) 
1

Вы можете использовать 2 линии deque и Counter:

from collections import Counter, deque 

lc=Counter() 
d=deque(maxlen=2) 
with open(fn) as f: 
    d.append(next(f)) 
    for line in f: 
     d.append(line) 
     lc+=Counter(["{},{}".format(*[e.rstrip() for e in d])]) 

>>> lc 
Counter({'fff,err': 2, 'ddd,fff': 1, 'bob,fff': 1, 'aaa,bob': 1, 'err,ddd': 1}) 

Вы можете также использовать regex с захватом смотреть вперед:

with open(fn) as f: 
    lc=Counter((m.group(1)+','+m.group(2),) for m in re.finditer(r"(\w+)\n(?=(\w+))", f.read())) 
+0

Могу ли я спросить, почему голос? – dawg

Смежные вопросы