【问题标题】:How to create all possible sentence of length 100 characters from a list of strings in Python如何从 Python 中的字符串列表中创建所有可能的长度为 100 个字符的句子
【发布时间】:2015-10-16 02:44:37
【问题描述】:

我正在尝试从给定的字符串列表中创建一个长度为 100 个字符的句子。长度必须正好是一百个字符。我们还必须使用排列找到所有可能的句子。每个单词之间必须有空格,并且不允许重复单词。名单如下:

['saintliness', 'wearyingly', 'shampoo', 'headstone', 'dripdry', 'elapse', 'redaction', 'allegiance', 'expressionless', 'awesomeness', 'hearkened', 'aloneness', 'beheld', 'courtship', 'swoops', 'memphis', 'attentional', 'pintsized', 'rustics', 'hermeneutics', 'dismissive', 'delimiting', 'proposes', 'between', 'postilion', 'repress', 'racecourse', 'matures', 'directions', 'bloodline', 'despairing', 'syrian', 'guttering', 'unsung', 'suspends', 'coachmen', 'usurpation', 'convenience', 'portal', 'deferentially', 'tarmacadam', 'underlay', 'lifetime', 'nudeness', 'influences', 'unicyclists', 'endangers', 'unbridled', 'kennedy', 'indian', 'reminiscent', 'ravish', 'republics', 'nucleic', 'acacia', 'redoubled', 'minnows', 'bucklers', 'decays', 'garnered', 'aussies', 'harshen', 'monogram', 'consignments', 'continuum', 'pinion', 'inception', 'immoderate', 'reiterated', 'hipster', 'stridently', 'relinquished', 'microphones', 'righthanders', 'ethereally', 'glutted', 'dandies', 'entangle', 'selfdestructive', 'selfrighteous', 'rudiments', 'spotlessly', 'comradeinarms', 'shoves', 'presidential', 'amusingly', 'schoolboys', 'phlogiston', 'teachable', 'letting', 'remittances', 'armchairs', 'besieged', 'monophthongs', 'mountainside', 'aweless', 'redialling', 'licked', 'shamming', 'eigenstate']

方法:

我的第一种方法是使用回溯和排列来生成所有句子。但我认为复杂性太高了,因为我的列表太大了。

我可以在这里使用任何其他方法或我可以在这里使用的一些内置函数/包吗? python中最好的方法是什么?任何指针都会在这里有所帮助。

【问题讨论】:

  • 你可以重复使用一个单词,还是不允许在句子中重复单词?另外,请注意,您可能会关闭此问题,因为您问的是一个广泛的问题。
  • 你可能会认为它有两个不同的问题:第一个,找到长度为 100 的单词的每个组合,第二个(更简单的)部分,获取每个组合的每个排列。
  • 我认为这是完全可能的。现在正在努力。令人兴奋的问题!
  • 如果这是您的核心问题,all((word in word_list) for word in dynamic_sentence.split()[:-1]) + 更多代码来解释截断位 + 更多代码来确定是否有重复项怎么样?正如 roeland 所提到的,生成(更不用说存储)所有排列是不可行的。
  • for-if 反模式。那你必须改变你的方法。在生成句子时已经应用该约束。将给定句子中的单词一一匹配。然后复杂度从 O(cⁿ) 下降到 O(n)

标签: python string list permutation


【解决方案1】:

你做不到。

想一想:即使选择 4 个单词,你也已经有 100 × 99 × 98 × 97 种可能性,几乎是 1 亿。

考虑到您的单词的长度,至少有 8 个单词适合句子。有 100 × 99 × 98 … × 93 种可能性。这大约是 7×10^15,一个完全不可行的数字。

【讨论】:

  • 当可能性范围太大时,智者会寻找合理的约束。
  • @NathanielFord 是的,但这个问题没有给出任何限制。即使这些限制将您限制为每一步只能使用 20 个单词,您仍然可以获得大量组合。
  • 虽然我最初支持 NathanielFord 大胆寻找解决方案,但我认为你是对的 @roeland。 Rakash,您是否考虑过解决方案所需的物理存储?根据 roeland 的计算,如果每个解决方案都是 10 字节,那么您的解决方案集将需要 7x10^10 GB 来存储。如果你不介意我问,你打算用它做什么?
  • 我们从不在这里存储任何东西,而是生成所有可能的句子来匹配我拥有的句子。
  • 同意生成所有可能的排列实际上是不可能的。换个角度来看,如果我们假设生成一百万个句子需要 1 秒,那么总工作需要 7x10^9 秒,也就是 200 年。
【解决方案2】:

这个问题和partitioning in number theory的问题类似。

使用问题陈述中编码的一些约束可以(大概)降低问题的复杂性:

  1. 单词列表中单词的长度。
  2. 字长重复:例如,长度为 8 的字重复 X 次。

这是一种可能的通用方法(需要一些改进):

  • 仅使用单词列表中单词的长度查找数字 100 的所有分区。 (您将从字长及其重复开始,而不是通过暴力破解所有可能的分区。)

  • 过滤掉重复长度值超过列表中单词重复长度值的分区。

  • 将单词组合应用于分区。一组相等长度的单词将映射到分区中的长度值。例如,假设您有分区(15+15+15+10+10+10+10+5+5+5),那么您将生成所有长度为 15 个单词超过 3、长度为 10 个单词超过 4、长度为 5 个单词超过 3 的组合。(我在这里忽略了空格分隔问题)。

  • 在所有分区上生成所有组合的排列。

【讨论】:

    【解决方案3】:

    简化一点:将所有字符串从“xxx”更改为“xxx”。然后将句子长度设置为 101。这允许您使用 len(x) 而不是 len(x)+1 并消除句子中最后一个单词的边缘情况。当您遍历并从左到右构建句子时,您可以根据您刚刚构建的句子消除会超出长度的单词。

    更新:

    认为这是一个以 n 为基数的问题,其中 n 是您拥有的单词数。创建一个初始化为 0 的向量 [注意:它只是固定大小来说明]:

    acc = [0, 0, 0, 0]

    这是你的“累加器”。

    现在构建你的句子:

    dict[acc[0]] + dict[acc[1]] + dict[acc[2]] + dict[acc[3]]

    所以,你得到able able able able

    现在增加 acc 中最重要的“数字”。这由“curpos”表示。这里的curpos是3。

    [0, 0, 0, 1]

    现在你得到able able able baker

    你不断碰撞 acc[curpos] 直到你点击 [0, 0, 0, n] 现在你有一个“执行”。通过将 curpos 递减到 2 来“向左走”。递增 acc[curpos]。如果它没有“执行”,则通过增加 curpos 并设置 acc[curpos] = 0 来“向右走”。如果你得到了执行,你会通过将 curpos 减少到 1 来执行“向左走”。

    这是一种回溯形式(例如“向左走”),但您不需要树。只是这个 acc 向量和一个具有三种状态的状态机:goleft、goright、test/trunc/output/inc。

    在“向右走”之后,curpos 将回到“最重要”的位置。即从 acc[0 到 curpos - 1] 构造的句子长度(没有加上最后一个词的长度)小于100。如果太长(例如已经超过100),做“向左走”。如果它太短(例如,您必须添加另一个词才能接近 [足够] 到 100),请执行“向右走”

    当你得到一个执行并且 curpos==0 时,你就完成了

    我最近设计了这个作为“吸血鬼数字挑战”的解决方案,你需要的遍历非常相似。

    【讨论】:

    • 这里的句子我删不掉。我必须截断多余的字符
    • “截断”是什么意思?你能提供一个发生截断的例子吗?
    • @RakeshRanjanSukla 所以,你的意思是“able baker charlie”被截断为“able baker charl”,这被认为是有效的?
    • 是的,如果你的句子有 100 个字符,你就停在那里,如果有多余的字符,就截断。
    • 但是下一句的创作会从你离开的地方开始。
    【解决方案4】:

    我不会提供一个完整的解决方案,但我会介绍我的想法。

    约束:

    • 可以立即丢弃超过 100 个字符的完整列表排列。 (好的,99 + len(longest_word))。)
    • 您实际上是在处理列表中元素的幂集子集。

    鉴于:

    • 构建动力集,但丢弃任何超过您的最大值的句子
    • 筛选出完全符合您需求的句子的最终集

    所以你可以拥有以下内容:

    def construct_sentences(dictionary: list, length: int) -> list:
        if not dictionary:
            return [(0, [])]
        else:
            word = dictionary[0]
            word_length = len(word) + 1
            subset_length = length - word_length
            sentence_subset = construct_sentences(dictionary[1:], subset_length)
            new_sentences = []
            for sentence_length, sentence in sentence_subset:
                if sentence_length + word_length <= length:
                    new_sentences = new_sentences + [(sentence_length + word_length, sentence + [word])]
            return new_sentences + sentence_subset
    

    我使用元组来记下列表的长度并使其易于比较。上述函数的结果将为您提供所有小于长度的句子列表(这是考虑潜在排列时的关键:100 相当短,因此有 大量 的排列可以容易丢弃)。下一步是简单地filter 任何不够长的句子(即 100 个字符)。

    请注意,此时您已拥有过滤条件的所有可能列表,但该列表可能会以2^n 的方式重新排序。尽管如此,这仍然是一个更易于管理的情况。使用 100 个单词的列表,每个单词平均少于 9 个字符,您在一个句子中的平均单词数等于 10。2^10 并不是世界上最糟糕的情况...

    当然,您必须针对截断情况对其进行修改,但这会让您大致了解。除非我完全错过了什么,这是总是可能的。我加倍认为有些地方出了问题,因为运行它会产生一个令人惊讶的短列表。

    【讨论】:

      【解决方案5】:

      您的问题规模太大,但如果 1) 您的实际问题的范围要小得多,和/或 2) 您有很多时间和一台速度非常快的计算机,您可以使用递归生成器生成这些排列.

      def f(string, list1):
          for word in list1:
              new_string = string + (' ' if string else '') + word
              # If there are other constraints that will allow you to prune branches,
              # you can add those conditions here and break out of the for loop
              if len(new_string) >= 100:
                  yield new_string[:100]
              else:
                  list2 = list1[:]
                  list2.remove(word)
                  for item in f(new_string, list2):
                      yield item
      
      x = f('', list1)
      for sentence in x:
          check(sentence)
      

      需要注意的是,如果最后的两个单词被截断以看起来相同,这可能会产生相同的句子。

      【讨论】:

        猜你喜欢
        • 2022-07-07
        • 2018-07-21
        • 2021-09-27
        • 2011-11-25
        • 1970-01-01
        • 1970-01-01
        • 2020-09-11
        • 2015-11-27
        • 1970-01-01
        相关资源
        最近更新 更多