Поиск слов, которые обращаются друг к другу в файле

55
5

Извините за этот вопрос новичков, только что начал. Я хочу, чтобы простая программа просматривала файл для обратных слов, поэтому написал этот источник, но он не работает. После того, как он войдет во второй цикл "для", он не вернется к первому циклу, а завершает работу программы. Любая подсказка?


def is_reverse(word1, word2):   
if len(word1) == len(word2):
if word1 == word2[::-1]:
return True
return False

fin = open('List.txt')
for word1 in fin:
word1 = word1.strip()
word1 = word1.lower()
for word2 in fin:
word2 = word2.strip()
word2 = word2.lower()
print word1 + word2
if is_reverse(word1, word2) is True:
print word1 + ' is the opposite of ' + word2


EDIT: Я попытался зациклить файл по списку и получил любопытный (мне) результат. Если я использую этот код, все работает:


def is_reverse(word1, word2):
if len(word1) == len(word2):
if word1 == word2[::-1]:
return True
return False

fin = open('List.txt')
fin2 = ['test1','test2','test3','test4','test5']
for word1 in fin:
word1 = word1.strip()
word1 = word1.lower()
for word2 in fin2:
word2 = word2.strip()
word2 = word2.lower()
print word1 + word2
if is_reverse(word1, word2) is True:
print word1 + ' is the opposite of ' + word2


Если я обмениваю ребро и fin2, первый цикл выполняет только одну итерацию. Может кто-нибудь объяснить мне, почему?

спросил(а) 2011-02-24T00:54:00+03:00 9 лет, 4 месяца назад
1
Решение
77

for word1 in fin повторяется по очереди, поэтому word1 - это действительно строка, а не слово. Это то, что вы намеревались?


for word2 in fin использует тот же самый итератор, поэтому я думаю, что он будет потреблять весь вход, а for word1 in fin будет выполняться только один раз.


Итак, самое простое изменение состоит в том, чтобы иметь два файла, file1 и file2, и повторно открыть файл2 для каждого прохода через цикл.


def is_reverse(word1, word2):   
if len(word1) == len(word2):
if word1 == word2[::-1]:
return True
return False

file1 = open('List.txt')
for word1 in file1:
word1 = word1.strip()
word1 = word1.lower()
file2 = open('List.txt')
for word2 in file2:
word2 = word2.strip()
word2 = word2.lower()
print word1 + word2
if is_reverse(word1, word2):
print word1 + ' is the opposite of ' + word2


Но, вероятно, лучший способ - прочитать файлы один раз в списке, а затем перебрать по списку, а не файл, например.


def is_reverse(word1, word2):
if len(word1) == len(word2):
if word1 == word2[::-1]:
return True
return False

file = open('List.txt')
words = list(file)
for word1 in words:
word1 = word1.strip()
word1 = word1.lower()
for word2 in words:
word2 = word2.strip()
word2 = word2.lower()
print word1 + word2
if is_reverse(word1, word2):
print word1 + ' is the opposite of ' + word2


Чтобы ответить на другой вопрос, почему вы можете перебирать один и тот же список дважды, но не над одним и тем же файлом:


A for element in iterable цикл запрашивает iterable для своего итератора, вызывая iterable.__iter__.

Когда Python запрашивает файл для своего итератора, файл возвращается сам. Это означает, что каждый итератор по файлу имеет одно и то же состояние/позицию.


>>> file = open('testfile.txt')
>>> it1 = iter(file)
>>> it2 = iter(file)
>>> id(it1)
3078689064L
>>> id(it2)
3078689064L
>>> id(file)
3078689064L

Когда вы запрашиваете список для своего итератора, вы получаете разные итераторы каждый раз с отдельной информацией о своей позиции.


>>> list = [1,2,3]
>>> it3 = iter(list)
>>> it4 = iter(list)
>>> id(it3)
3078746156L
>>> id(it4)
3078746188L
>>> id(list)
3078731244L

Postscript


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


Здесь намного быстрее. Измените List.txt на очень большой файл, например. /usr/share/dict/words в системе Linux, чтобы понять, что я имею в виду.


words = []
wordset = set(())

file = open('List.txt')
for line in file:
word = line.strip('\n')
words.append(word)
wordset.add(word)

for word in words:
reversed = word[::-1]
if reversed in wordset:
print word + ' is the opposite of ' + reversed

ответил(а) 2011-02-24T00:58:00+03:00 9 лет, 4 месяца назад
55

Если вы действительно хотите сравнить список с самим собой, вы можете избежать итерации путем тестирования значения в наборе:


def getWords(fname):
with open(fname) as inf:
words = list(w.strip().lower() for w in inf)
ws = set(words)
words = list(ws)
words.sort()
return words, ws

def wordsInReverse(words, wordset):
for w in words:
rw = w[::-1] # reverse the string
if rw in wordset:
yield w,rw

def main():
words, wordSet = getWords('List.txt')

for w,rw in wordsInReverse(words, wordSet):
if rw >= w: # don't print duplicates
print('{0} is the opposite of {1}'.format(w, rw))

if __name__=="__main__":
main()

и перекрестно сравнить два файла:


from itertools import chain

def main():
words1, wordSet1 = getWords('List1.txt')
words2, wordSet2 = getWords('List2.txt')

for w,rw in chain(wordsInReverse(words1, wordSet2), wordsInReverse(words2, wordSet1)):
print('{0} is the opposite of {1}'.format(w, rw))

ответил(а) 2011-02-24T01:47:00+03:00 9 лет, 4 месяца назад
39

Не нужно читать файл более одного раза.



- Клаус Бисков Хоффманн


Это означает, что он перегружает время, чтобы повторить два раза по словам: если файл содержит 1000 слов, обращение каждого слова будет потенциально сравниваться с 1000 словами, то есть 1000000 сравнений в общей сложности;


Здесь код с одной итерацией, словарь напоминает, что он уже видел


with open('palindromic.txt') as f:
ch = f.read()
li = [ w for w in ch.split() if len(w)>1 ]

dic ={}
pals = set([])

for line in li:
word = line.strip().lower()
if len(word)>1:
if word not in dic:
dic[word] = 1
if word[::-1] in dic and word[::-1]!=word:
pals.add(word)
else:
dic[word] += 1

for w in pals:
print w,dic[w],' ',w[::-1],dic[w[::-1]]


[w для w в ch.split(), если len (w) > 1] должно быть улучшено для удаления скобок, апострофов и т.д. из каждого слова

ответил(а) 2011-02-24T05:05:00+03:00 9 лет, 4 месяца назад
39

Я предполагаю, что вы повторяете "плавник" в обеих циклах (хотя ваш примерный код имеет таинственную переменную "x" в первом цикле). Вместо этого попробуйте использовать отдельный дескриптор файла в каждом цикле, например:


fin1 = open("list.txt")
for word1 in fin1:
fin2 = open("list.txt")
for word2 in fin2:
...etc...

ответил(а) 2011-02-24T00:59:00+03:00 9 лет, 4 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема