【问题标题】:recursive function for wordsearch用于单词搜索的递归函数
【发布时间】:2018-05-31 22:39:31
【问题描述】:

给定字母:字母示例

letters = 'hutfb' 

我收到了一个包含单词列表的文件。

我需要编写一个递归函数,让我可以检查字母的所有可能性。如果可能在文件中的单词列表中,我需要打印该特定单词。

所以对于给定的字母

他们可以创造单词:

  • 一个
  • 交流
  • 行动
  • 出租车

等等等等

字母组成的每个组合我都需要检查文件以查看它是否是有效的单词。如果是我需要打印它们。

我不知道怎么开始写这个函数。

【问题讨论】:

  • 您的第一步是明确要求。一个字母可以在单词中重复吗?例如,tat 是否可以用于您给定的示例?
  • 不,除非字母 = t t a c
  • 似乎您正在查看数组的子集。看看stackoverflow.com/questions/26332412/…
  • @Teomanshipahi:OP 正在查看数组所有非空子集的所有排列。

标签: python python-3.x file recursion


【解决方案1】:

我同意@dparolin 关于处理单词文件以查看单词是否符合字母,而不是生成可能的单词并查看它们是否在文件中。这使我们不必将文件读入内存,因为我们一次只需要检查一个单词。并且可以通过递归测试来完成:

letters = 'catbt'

def is_match(letters, word):

    if not word:
        return True

    if not letters:
        return False

    letter = letters.pop()

    if letter in word:
        word.remove(letter)

    return is_match(letters, word)

with open('words.txt') as words:
    for word in words:
        word = word.strip()

        if is_match(list(letters), list(word)):
            print(word)

示例用法

% python3 test.py
act
at
bat
cab
cat
tab
tact
%

我们应该能够毫无问题地处理大量信件。

【讨论】:

  • 这在文件很小的情况下有效,但如果文本文件太长,则会出现错误。
  • @thecode,我用一个包含超过 200,000 个单词的文件进行了测试,每行一个单词。您使用什么格式和大小的文件?
  • @thecode,我用一个包含超过 300,000 个单词的文件重新测试了这段代码,并且字母表增加了三倍为letters,它运行良好。递归深度不应超过lettersword 中的较短者,这必须接近1,000 个字符才能导致RecursionError。你修改代码了吗?你用什么letters?文件中是否有某种异常条目导致代码跳闸?
【解决方案2】:

不幸的是,我现在对递归函数无能为力,但考虑到如果在创建过程中不过滤,更多的字母/字符很容易爆炸成数十亿个潜在组合,我有一个通过迭代已知单词的古怪替代方案。无论如何,这些都必须在内存中。

[编辑] 删除了排序,因为它并没有真正提供任何好处,修复了我在迭代时错误地设置为 true 的问题

# Some letters, separated by space
letters = 'c a t b'
# letters = 't t a c b'

# # Assuming a word per line, this is the code to read it
# with open("words_on_file.txt", "r") as words:
#     words_to_look_for = [x.strip() for x in words]
#     print(words_to_look_for)

# Alternative for quick test
known_words = [
    'cat',
    'bat',
    'a',
    'cab',
    'superman',
    'ac',
    'act',
    'grumpycat',
    'zoo',
    'tab'
]

# Create a list of chars by splitting
list_letters = letters.split(" ")

for word in known_words:
    # Create a list of chars
    list_word = list(word)
    if len(list_word) > len(list_letters):
        # We cannot have longer words than we have count of letters
        # print(word, "too long, skipping")
        continue

    # Now iterate over the chars in the word and see if we have
    # enough chars/letters
    temp_letters = list_letters[:]

    # This was originally False as default, but if we iterate over each
    # letter of the word and succeed we have a match
    found = True
    for char in list_word:
        # print(char)
        if char in temp_letters:
            # Remove char so it cannot match again
            # list.remove() takes only the first found
            temp_letters.remove(char)
        else:
            # print(char, "not available")
            found = False
            break

    if found is True:
        print(word)

您可以从 itertools documentation 复制和粘贴产品功能并使用 ExtinctSpecie 提供的代码,它没有进一步的依赖关系,但是我发现不调整它会返回所有潜在选项,包括我没有立即理解的字符重复。

def product(*args, repeat=1):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = [tuple(pool) for pool in args] * repeat
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

【讨论】:

  • 因为您最终只想打印字母中可能出现的单词,这些字母也出现在实际/正确/已知单词列表中,所以我选择了这条路径。要成为这样的匹配项,我会遍历每个单词可能是有效的,然后检查是否所有这些字符都包含在首字母中,以便于排序。仍然认为这会产生所要求的结果。如果没有这样的“字典”,您将无法从所提供的字母中知道所有可能的单词。
  • 其实我只是重新测试过,它的工作不够准确,例如尽管只有一个“b”,但我的代码将接受“tabb”,并且我认为存在与删除字符有关的问题。将尝试提供更新 + 确保您可以看到所有排列,以备不时之需。
  • 感谢您的澄清,但是如果不首先使用 known-words 文件或使用其他“算法”来猜测它可能是一个词,您怎么能知道它是一个潜在的词。与字母一起工作的功能必须具备某种知识,然后才能有选择地检查您的单词文件。如果这很重要,我相信可以做到,但肯定会比迭代甚至超过一百万个已知单词要复杂得多。
  • 该文件有一个有效单词列表。所以如果组合在文件中,那么这意味着它是一个有效的词。
  • 您能否详细说明您是否有内存限制(例如必须在具有 512K 内存的嵌入式 MicroPython 上运行或类似的东西?因为我还不能评论 @cdlane 答案,我想了解这个大小会中断。鉴于该答案,它实际上应该在内存中一次只有一行(单词)。如果您尝试过并且有错误消息,请告诉我们。
【解决方案3】:
import itertools
str = "c a t b"
letters = list(str.replace(" ",""))
words_to_look_for = []

for index, letter in enumerate(letters):
    keywords = [''.join(i) for i in itertools.product(letters, repeat = index+1)]
    words_to_look_for.extend(keywords)

print(words_to_look_for)

https://stackoverflow.com/questions/7074051/....

【讨论】:

    【解决方案4】:

    如上所述,这不会仅适用于你双手可数的字母数量。有太多的可能性要检查。但是,如果您要尝试此操作,代码将如下所示。

    letters = ['a', 'b', 'c']
    
    def powerset(letters):
        output = [set()]
        for x in letters:
            output.extend([y.union({x}) for y in output])
        return output
    
    for subset in powerset(letters):
        for potential_word in map(''.join, itertools.permutations(list(subset))):
            # Check if potential_word is a word
    

    这不会尝试包含重复字母的单词(那将是另一层疯狂),但它会尝试所有可能的潜在单词,这些单词可能由您以任意顺序输入的字母的子集构成。

    [编辑] 刚刚意识到您要求递归解决方案。不知道是否需要这样做,但是可以将 powerset 函数更改为递归。不过,我认为这会使它变得更丑陋,更难理解。

    【讨论】:

      猜你喜欢
      • 2013-05-12
      • 2015-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-30
      • 2013-06-11
      • 1970-01-01
      • 2018-09-28
      相关资源
      最近更新 更多