Поиск слов, которые противоположны друг другу в файле - PullRequest
1 голос
/ 24 февраля 2011

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

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 

РЕДАКТИРОВАТЬ: Я пытался зациклить файл против списка, и получил любопытный (для меня) результат.Если я использую этот код, то все работает:

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

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

Ответы [ 4 ]

3 голосов
/ 24 февраля 2011

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 

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

Цикл 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

Постскриптум

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

Вот способ, которым этонамного быстрее.Измените 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
1 голос
/ 24 февраля 2011

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

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))        
0 голосов
/ 24 февраля 2011

Нет необходимости читать файл более одного раза.

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

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

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

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] необходимо улучшить, чтобы убрать скобки, апострофы и т. д. из каждого слова

0 голосов
/ 24 февраля 2011

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

fin1 = open("list.txt")
for word1 in fin1:
    fin2 = open("list.txt")
    for word2 in fin2:
        ...etc...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...