繁体   English   中英

排列列出随机结果

[英]Permutations list random results

有人可以帮忙处理这段代码吗,我需要它来保存一个排列列表和每个排列后的一个数字,并随机打印让我们说其中的 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)



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很有用。


对于重复计数,您需要将random.sample替换为random.choices (以允许重复),然后使用collections.Counter对其进行计数。

from itertools import permutations
from random import choices
from collections import Counter

perms = choices(list(enumerate(permutations(word))), k=20)
counts = Counter(counts)

for perm, count in counts.items():
    print("".join(perm), count)

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

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 ,则输出将与list(permutations(...)) ) 的第 2、5 和 9 个元素相同list(permutations(...))

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM