Python:字谜查找器

Python: anagram finder

我有一个基本字符串和一个包含特定单词的字典。我想使用字典中的单词找到基本字符串的所有可能的字谜。

例如:

base_string = 'Oscar Wilde'
words = {1: 'sidecar', 2: 'owl', 3: 'low', 4: 'acid', 5: 'bread', 6: 'slower'}

现在我想看看我可以用字典中的单词拼出多少种不同的字谜。所需的输出将是 'sidecar owl'、'sidecar low'、'acid slower'。

我将字符串转换为列表,如下所示:

letters = ['o', 's', 'c', 'a', 'r', 'w', 'i', 'l', 'd', 'e']

我希望我的代码能检查字典中每个单词的组合。我有一个计数器,可以计算尝试组合的次数。

anagrams = []
counter = 0
for i in range(1, len(words)+1):
    anagram = ''
    for i in range(i+1, len(words)+1):
        if contain(letters, words[i]):  #if word is contained in the base string
            for i in words[i]:  #remove each letter of the word from the list of letters of the base string 
                letters.remove(i)
            anagram += words[i] + ' '
    if len(letters) >= 1:  #if all the letters are not used, it's not an anagram
        counter += 1
    if len(letters) == 0:  #if all the letters are used, it's an anagram
        anagrams.append(anagram)

print anagrams

def contain(list1, list2):
    counter1 = Counter(list1)
    counter2 = Counter(list2)
    for k in counter2:
        if counter2[k] != counter1.get(k):
            return False
    return True

findanagram()

我收到 anagram += words[i] + ' '

的 KeyError

我希望我已经解释得足够清楚了。

示例实现

这是最简单但远非最有效的方法。它将搜索两个单词的字谜:

from itertools import combinations
from collections import Counter

name = 'Oscar Wilde'
words = ['sidecar', 'owl', 'low', 'acid', 'bread', 'slower']

letter_counter = Counter(name.replace(' ', '').lower())
for ws in combinations(words, 2):
    if Counter(''.join(ws)) == letter_counter:
        print(' '.join(ws))

# sidecar owl
# sidecar low
# acid slower

它基本上与您的预期相同,但更 pythonic 方式。

您的实施存在一些问题:

  • 您的包含函数无法正常工作。它会给 contain('a', 'aa') 错误,因为它检查出现的字母是否相等。
  • 你的两个 for 循环使用相同的 i 索引变量。
  • 您在数组上使用基于 1 的索引 (range(1, len(words) + 1)),但 python 数组是基于 0 的索引 (range(0, len(words)))

个人比较推荐hege的方案。它简单、直截了当、切中要害。但是,如果您计划使用大型词典并多次重复此过程,则可能需要一种更快的方法。

我们的想法是将每个字母与一个质数相关联,即 a = 2、b = 3、c = 5 等。获得数字 25 的唯一方法是将字母 c 在您的单词。通过将一个单词中的所有字母相乘,您可以获得它的 ID 号。自然地,该词的任何字谜也会产生相同的 ID。

因此,您只需检查单词 A 和 B 的 ID 的乘积是否等于您感兴趣的单词的 ID。

from itertools import combinations
from string import ascii_lowercase as alphabet

primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
          47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
letter_id = dict(zip(alphabet, primes))

def get_word_id(word):
    product = 1
    for letter in word:
        product *= letter_id[letter]
    return product

words = ['sidecar', 'owl', 'low', 'acid', 'bread', 'slower']
dictionary = {}
for w in words:
    dictionary[w] = get_word_id(w)

base_string = 'Oscar Wilde'

for comb in combinations(words, 2):
    comb_id = 1
    for word in comb:
        comb_id *= dictionary[word]
    if get_word_id(base_string.replace(' ', '').lower()) == comb_id:
        print comb

正如我在 hege 的回答中评论的那样,如果您对不止对感兴趣,您可以像这样概括组合

for no_of_words in xrange(1, len(words)+1):
    for comb in combinations(words, no_of_words):
        ...