[英]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.comb
和math.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.