生成所有排列的随机子集

时间:2018-02-12 11:18:33

标签: python permutation itertools

我正在寻找一种随机抽样所有排列的固定长度子集的方法。

import itertools
from random import shuffle

mylist = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T']

APPROACH A

方法A下面的问题是排列过于相似。

a_pre = itertools.permutations(mylist,20)
a = itertools.islice(a_pre,3)

list(a)
  

[' A',' B',' C',' D',' E',& #39; F',' G',' H','我',' J',' K&# 39;,' L',' M',' N',' O',' P',&# 39; Q',' R',' S'' T']

     

[' A',' B',' C',' D',' E',& #39; F',' G',' H','我',' J',' K&# 39;,' L',' M',' N',' O',' P',&# 39; Q',' R',' T',' S']

     

[' A',' B',' C',' D',' E',& #39; F',' G',' H','我',' J',' K&# 39;,' L',' M',' N',' O',' P',&# 39; Q',' S',' R',' T']

APPROACH B

方法B使我更接近我期望的结果,但是这里总是存在在列表之间产生相同排序的风险,因此这种方法是不可行的。

#repeat n=3 times

shuffle(mylist)
print(mylist)
  

[' J',' B',' M',' A',' O',& #39; C',' K',' S',' H',' Q',' N&# 39;,' T',' R',' D',' G',' P',&# 39;我',' E',' F',' L']

     

[' R',' O',' C','我'' G',& #39; E',' Q',' L',' P',' J',' F&# 39;,' N',' A',' B',' H',' T',&# 39; D',' K',' M',' S']

     

[' L',' O','我',' G',' B',& #39; E',' R',' A',' D',' N',' J&# 39;,' S',' H'' F',' K',' M',&# 39; Q',' T',' C',' P']

4 个答案:

答案 0 :(得分:3)

  

但是这里总是存在在列表之间产生相同排序的风险,所以这种方法是不可行的。

您可以使用元组(因为列表不可用)和设置(因此没有重复/相同的列表)来解决这个问题:

let itemProvider = PasswordShareItemsProvider(password: password)
let activityViewController = UIActivityViewController(activityItems: [itemProvider], applicationActivities: nil)

编辑:正如@tobias_k指出的那样:

  

对于给定的列表,有20个! = 2432902008176640000不同的排列,所以碰撞真的不太可能。

答案 1 :(得分:2)

考虑一下itertools random_permutation recipe

来自文档:

def random_permutation(iterable, r=None):
    "Random selection from itertools.permutations(iterable, r)"
    pool = tuple(iterable)
    r = len(pool) if r is None else r
    return tuple(random.sample(pool, r))

<强>代码

import string

import more_itertools as mit


iterable = string.ascii_uppercase[:-6]
[random_permutation(iterable) for _ in range(3)]

输出

[('M', 'K', 'Q', 'A', 'I', 'J', 'H', 'T', 'C', 'E', 'P', 'L', 'B', 'N', 'G', 'F', 'S', 'D', 'O', 'R'), 
 ('A', 'G', 'I', 'S', 'E', 'T', 'B', 'Q', 'D', 'M', 'C', 'O', 'J', 'H', 'N', 'F', 'K', 'P', 'R', 'L'), 
 ('C', 'S', 'O', 'H', 'I', 'K', 'A', 'G', 'D', 'B', 'R', 'E', 'L', 'T', 'M', 'N', 'F', 'P', 'Q', 'J')]

more_itertoolsimplements this recipe为您提供的第三方库。

答案 2 :(得分:0)

我认为你的问题是one I had的一个特例,因为k = N. 基于此,这里所述的两种解决方案应该适用。第一个是慢一点:)

所以随机抽样(你也暗示你的问题,只是丢弃重复......)似乎是现在唯一的答案。

看看这个问题或者更普遍的问题是否存在生成解决方案将会非常有趣...... 以下是基于该答案的代码:

import itertools
from random import shuffle

mylist = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T']
n=len(mylist)
k = n
m = 5
samples = set()
tries = 0
while len(samples) < m:
    samples.add(tuple(random.sample(mylist,k)))
    print (len(samples))

print(samples)
print(tries)

答案 3 :(得分:0)

您可以使用它来生成number - N元素的词典编排:

def permutation_from_int(N, number):
    '''
    get the number-th lexicographic permutation of length N.

    N: the length of the permutation
    0 <= number <= factorial(N) -1: the number of the desired
    permutation
    '''

    # assert 0 <= number < factorial(N)

    ret = [None] * N
    select = list(range(N))

    for i in range(N - 1, -1, -1):
        index, number = divmod(number, factorial(i))
        element = select[index]
        ret[N - 1 - i] = element
        select.remove(element)
    return ret

那么你只需要生成(并保留set - 如果你想避免重复一样)代表排列的随机整数:

N_TESTS = 17
strg = 'ABCD'
N = len(strg)
N_MAX = factorial(N)
seen = set()

for _ in range(N_TESTS):
    number = randrange(N_MAX)
    while number in seen:
        number = randrange(N_MAX)
    seen.add(number)
    perm = permutation_from_int(N, number)
    print(''.join(strg[i] for i in perm))

请注意,如果测试的数量大于所有排列的空间,这可能永远循环...

打印(例如):

DACB
DBCA
BADC
BDCA
DCAB
DABC
CADB
DBAC
DCBA
...

但正如其他答案中所提到的:如果你有20个元素的排列,那么重复置换的几率非常小!