【问题标题】:Permutations list random results排列列出随机结果
【发布时间】:2022-06-15 01:09:33
【问题描述】:

有人可以帮忙处理这段代码吗,我需要它来保存排列列表和每个排列后的数字,并随机打印 20 个。

目前它仅适用于第一部分.. 它打印给定单词的排列,但我不知道要合并评论的后半部分,它必须进行计数并获取随机结果。

假设您想要“老鼠”的排列,应该出现 24 行,这应该是代码后半部分(最后 6 行)的输入。使用 sys.stdin 必须将这 24 行添加到计数列表中。每行都有一个数字 (1-24),然后随机选择其中的 20 个(导入数学,必须使用随机数)。

输入是一个词, 输出必须是 20 个随机排列。

任何建议将不胜感激,谢谢。

import sys, re



def gen_permutations(a, n):
 
    if n == 0:
        print(''.join(a))
    else:
        for i in range(n):
            gen_permutations(a, n-1)
            j = 0 if n % 2 == 0 else i
            a[j], a[n] = a[n], a[j]
        gen_permutations(a, n-1)

if len(sys.argv) != 2:
    sys.stderr.write('one argument only\n')
    sys.exit(1)


word = sys.argv[1]

gen_permutations(list(word), len(word)-1)

#counts = {}
#for line in sys.stdin:
#     for word in re.findall(r'[a-z\']+', line.lower()):
#         counts[word] = counts.get(word, 0) + 1
#         for word, count in sorted(counts.items()):
#             print (word, count)



【问题讨论】:

  • 报告counts 内容的最后两行位于构建counts 的循环内。您的代码不应该等到所有输入都处理完毕后再报告它吗?
  • 假设你想要“老鼠”的排列,应该出现 24 行,这应该是代码后半部分(最后 6 行)的输入。使用 sys.stdin 必须将这 24 行添加到计数列表中。每行都有一个数字 (1-24),然后随机选择其中的 20 个。
  • edit 解释您的问题,而不是在评论中补充。样本输入和输出也会有所帮助。 每个列表都有一个编号:是用户提供的还是代码应该这样做?你的描述充满了被动(被给予,被选择)。避免这些会更清楚地说明需求是什么。

标签: python random permutation


【解决方案1】:

作为替代答案,从更数学的角度解决如何解决这个问题:

from math import factorial
from random import sample


def solve(word, count):
    factorials = [factorial(x) for x in range(len(word))][::-1]
    indices = sample(range(factorial(len(word))), count)
    
    output = []
    for index in indices:
        alphabet = list(word)
        result = ""
        for fact in factorials:
            q, index = divmod(index, fact)
            result += alphabet.pop(q)
        output.append(result)
    return output

示例用法

>>> print(solve("abcde", 10))
['bdeca', 'bdcea', 'decba', 'caebd', 'daceb', 'cedba', 'cdbea', 'ebcda', 'decab', 'becad']

这项工作的方式是首先选择要选择的排列索引,然后计算与这些索引关联的排列。 n 字符的排列具有n! 排列,所以如果我们的索引大于那个,我们将需要一个额外的字符。我们(从概念上)换掉前导字符,减去我们跳过的n! 排列,看看这个新的索引值是否小于n! - 冲洗并重复直到它是。然后我们在 n-1 上重复,以此类推,直到我们构建了整个排列,然后对其余的索引这样做。

我使用的索引映射也对应itertools.permutations的顺序——如果你有[2, 5, 9]indices,输出将与@987654331的第2、5、9个元素相同@。

这种实现对于小样本量来说要快得多,因为它的时间复杂度为O(C * S) - 至少如果您使用足够小的数字,您可以将乘法视为O(1)。否则,阶乘预计算将是时间复杂度中不可忽略的一部分。

如果您需要排序的结果,您可以在迭代之前对indices进行排序,结果将按排序顺序返回。

【讨论】:

    【解决方案2】:
    from itertools import permutations
    from random import sample
    
    word = ...
    
    perms = sample(list(enumerate(permutations(word))), 20)
    for id_val, perm in perms:
        print("".join(perm), id_val)
    

    单词“abcd”的输出:

    bcad 8
    bdca 11
    cdba 17
    cbad 14
    acdb 3
    adcb 5
    abcd 0
    dbac 20
    dbca 21
    cabd 12
    abdc 1
    bacd 6
    cbda 15
    cadb 13
    badc 7
    bdac 10
    cdab 16
    dcba 23
    dcab 22
    dacb 19
    

    注意:这(以及您的原始实现)会生成 所有 排列,即使是那些未在输出中使用的排列。这意味着对于大字,运行时间比必要的要长得多,本质上是 O(n!)。

    如果您发现遇到性能问题,则应改为使用random.choices 选择 20 个索引,然后生成与这些索引对应的特定排列。您会发现 math.combmath.factorial 对此很有用。

    【讨论】:

    • 是的,性能是我一开始没有想到的。如果您使用的单词长度超过 4 个字符。你能举一个 math.comb 和 math.factorial 的例子吗?此外,我不允许使用 itertools.permutations.. 我将不得不坚持上面的示例进行排列。否则,这是一个非常优雅的解决方案。
    • @M8Dim 看到我的其他答案。方法太不同了+太长了,无法合并到这个中
    • “0”和“19”重复..如何避免?
    • @M8Dim 将random.choices(..., k=20) 替换为random.sample(..., 20)
    • 我在这篇文章中忘记了这一点 - 另一个答案正确/没有创建重复
    猜你喜欢
    • 2012-06-24
    • 1970-01-01
    • 2021-07-28
    • 2013-02-08
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    相关资源
    最近更新 更多