Найти анаграммы данного слова в файле

Итак, для класса у нас есть проблема, когда нам нужно ввести слово, и из данного текстового файла (wordlist.txt) будет составлен список с использованием любых анаграмм этого слова, найденных в файле.

Мой код пока выглядит так:

def find_anagrams1(string):
"""Takes a string and returns a list of anagrams for that string from the wordlist.txt file.

string -> list"""
anagrams = []

file = open("wordlist.txt")
next = file.readline()
while next != "":
    isit = is_anagram(string, next)
    if isit is True:
        anagrams.append(next)
    next = file.readline()
file.close()

return anagrams

Каждый раз, когда я пытаюсь запустить программу, она просто возвращает пустой список, несмотря на то, что я знаю, что в нем присутствуют анаграммы. Любые идеи о том, что не так?

P.S. Функция is_anagram выглядит так:

def is_anagram(string1, string2):
"""Takes two strings and returns True if the strings are anagrams of each other.

list,list -> string"""
a = sorted(string1)
b = sorted(string2)
if a == b:
    return True
else:
    return False

Я использую Python 3.4


person lilbanili    schedule 05.03.2015    source источник
comment
это помогает? stackoverflow.com/questions/22304231 /   -  person JGerulskis    schedule 05.03.2015
comment
Я думаю, что символ новой строки может быть причиной проблемы. Вам нужно удалить его с конца строки.   -  person Ankit Jaiswal    schedule 05.03.2015


Ответы (3)


Проблема в том, что вы используете функцию readline. Из документации:

file.readline = readline(...)
readline([size]) -> next line from the file, as a string.

Retain newline.  A non-negative size argument limits the maximum
number of bytes to return (an incomplete line may be returned then).
Return an empty string at EOF.

Ключевой информацией здесь является «Сохранить новую строку». Это означает, что если у вас есть файл, содержащий список слов, по одному на строку, каждое слово будет возвращено с терминальной новой строкой. Итак, когда вы звоните:

next = file.readline()

Вы не получаете example, вы получаете example\n, так что это никогда не будет соответствовать вашей входной строке.

Простое решение — вызвать метод strip() для строк, считанных из файла:

next = file.readline().strip()
while next != "":
    isit = is_anagram(string, next)
    if isit is True:
        anagrams.append(next)
    next = file.readline().strip()
file.close()

Однако с этим кодом есть несколько проблем. Начнем с того, что file — ужасное имя для переменной, потому что оно будет маскировать модуль Python file.

Вместо повторного вызова readline() вам лучше воспользоваться тем фактом, что открытый файл является итератором, который выдает строки файла:

words = open('wordlist.txt')
for word in words:
    word = word.strip()
    isit = is_anagram(string, word)
    if isit:
      anagrams.append(word)
words.close()

Также обратите внимание, что поскольку is_anagram возвращает True или False, вам не нужно сравнивать результат с True или False (например, if isit is True). Вы можете просто использовать возвращаемое значение отдельно.

person larsks    schedule 05.03.2015
comment
Ах я вижу! Большое спасибо, это было невероятно полезно! - person lilbanili; 05.03.2015

Yikes, не используйте циклы for:

import collections

def find_anagrams(x):
    anagrams = [''.join(sorted(list(i))) for i in x]
    anagrams_counts = [item for item, count in collections.Counter(anagrams).items() if count > 1]
    return [i for i in x if ''.join(sorted(list(i))) in anagrams_counts]
person A.Kot    schedule 08.08.2017

Вот еще одно решение, которое я считаю довольно элегантным. Это выполняется за O(n * m), где n — количество слов, а m — количество букв (или среднее количество букв/слов).

# anagarams.py

from collections import Counter
import urllib.request


def word_hash(word):
  return frozenset(Counter(word).items())

def download_word_file():
  url = 'https://raw.githubusercontent.com/first20hours/google-10000-english/master/google-10000-english-no-swears.txt'
  urllib.request.urlretrieve(url, 'words.txt')

def read_word_file():
  with open('words.txt') as f:
    words = f.read().splitlines()
  return words


if __name__ == "__main__":
  # downloads a file to your working directory
  download_word_file()

  # reads file into memory
  words = read_word_file()

  d = {}

  for word in words:
    k = word_hash(word)
    if k in d:
      d[k].append(word)
    else:
      d[k] = [word]

  # Prints the filtered results to only words with anagrams
  print([x for x in d.values() if len(x) > 1])
person Jordan    schedule 20.03.2021