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