TypeError: объект 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);

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

7 ответов


вам просто нужно отслеживать предыдущую строку, объект file возвращает свой собственный итератор, поэтому вам не нужен iter или readlines вообще, называть далее еще в самом начале создания переменной prev тогда просто продолжайте обновлять prev в цикле:

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})

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

С line является iterв состоянии и __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)

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

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

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:]))

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


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

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() вы также сохраняете '\n ' каждой строки. Возможно, вы захотите сначала снять его:

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

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

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()))

как уже упоминалось, вы не можете использовать next на строке, которая является строкой. Вы можете использовать itertools.tee чтобы создать два независимых итератора из объекта file, используйте 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)))

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


ваша ценность 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}) не работает. Вы пропустите возможные комбинации.