【问题标题】:Python: anagram finderPython:字谜查找器
【发布时间】:2016-03-18 01:54:20
【问题描述】:

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

例如:

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

现在我想看看我可以用字典中的单词组成多少不同的字谜。所需的输出将是“sidecar owl”、“sidecar low”、“acid slow”。

我把字符串变成了一个列表,看起来像:

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

我希望我已经足够清楚地解释了自己。

【问题讨论】:

    标签: python python-2.7 anagram


    【解决方案1】:

    我个人会推荐 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):
            ...
    

    【讨论】:

    • 计算所有尝试过的组合的最佳方法是什么?我尝试将 'counter += 1' 放在组合中的梳子(单词,no_of_words)下,但它不起作用
    • 你是否在外循环外初始化了计数器?到底是怎么不工作的?有错误吗?还有一个简单的equation 会告诉你组合的数量。
    • 我确实在循环之前将它初始化为counter = 0,它输出0,好像什么都没发生
    • 我无法复制您的问题。您可以上传您在 pastebin.com 上使用的确切代码块进行检查吗?
    【解决方案2】:

    示例实现

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

    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
    

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

    您的实施存在一些问题:

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

    【讨论】:

    • 不清楚OP是否只想要单词对,但你可以用for no_of_words in xrange(1, len(words)+1): for ws in combinations(words, no_of_words): ...概括组合
    • 对,但是我不想写这么低效的算法。我将更新我的答案以明确它会找到对!
    • 匿名投票者是否对我有一些建议,或者至少解释一下为什么他不喜欢我的解决方案?
    • 这个解决方案非常干净。 +1
    猜你喜欢
    • 2010-10-28
    • 2014-04-13
    • 2012-01-01
    • 2017-04-05
    • 2011-12-07
    • 2013-01-11
    • 2022-01-21
    • 2019-07-07
    • 1970-01-01
    相关资源
    最近更新 更多