如何从itertools.permutations(k)
逐个随机选择所有结果(无重复)?或者:如何构建随机排列的生成器?像shuffle(permutations(k))
这样的东西。我正在使用Python 2.6。
是的,如果shuffle(r)
可以使用r = list(permutations(k))
,但是当len(k)
提升到10以上时,这样的列表会占用太多时间和内存。
感谢。
答案 0 :(得分:3)
这给出了列表的第n个排列
def perm_given_index(alist, apermindex):
alist = alist[:]
for i in range(len(alist)-1):
apermindex, j = divmod(apermindex, len(alist)-i)
alist[i], alist[i+j] = alist[i+j], alist[i]
return alist
其中apermindex
介于0
和factorial(len(alist))
答案 1 :(得分:2)
我不知道python是如何实现其shuffle算法的,但是线性时间的缩放如下,所以我不明白为什么10的长度是如此重要(除非我误解了你的问题?):
对于不同的排列,只需再次运行相同的算法。
答案 2 :(得分:2)
如果不编写自己的permutations
版本,就没有办法做你所要求的。
考虑一下:
permutations
的生成器对象。由于我有一个生成器,如果随机函数在列表末尾附近选择一个条目,唯一的方法就是通过所有先前的条目并将它们丢弃,这是不好的,或者存储它们在列表中,当你有很多选择时,你已经指出了这个问题。
您是要绕过每个排列还是只使用几个?如果是后者,那么随机生成每个新排列更有意义,然后在set
中存储您之前看到的那些排列。如果不使用那么多,那么每次发生碰撞时必须创建新排列的开销将非常低。
答案 3 :(得分:1)
有些算法可以为您提供排列。你可以在wikipedia article找到一个在线性时间内工作的。
使用yield
在python中实现它,以实现高效的顺序生成。但是,如果您希望随机选择而不重复,则必须生成列表,或使用Dan发布的算法并记住您已选择的数字。
答案 4 :(得分:1)
您正在寻找的是Lehmer指数。 Lehmer索引可以从随机整数生成,然后可以转换为特定的排列,所有这些都不需要生成一组排列,而实际上只使用其中一个。
知道要n个对象的n个排列之一,就知道有n个!其中。您需要做的就是选择一个介于0和n!-1之间的数字,并使用Lehmer代码将以10为底的索引转换为Lehmer代码,然后该代码将成为阶乘基数。这些数字也称为factoradics。
例如,假设要为3个索引为0、1和2的对象选择特定的随机排列。(0,1,2)(全部按顺序)的Lehmer代码为(0,0,0 ),因为前两个零是0,所以前两个零都是重要的!始终为零的地方。因此,只需考虑前两个。然后,用于排列(0,1,2)的Lehmer代码将为(0,0),因为每个数字子集中的求反数为0,即(0,1,2)没有求反(因为0 <1 < 2)和(1,2)没有反演(因为1 <2)。
另一个例子是(2,1,0)。要获得该代码的Lehmer代码,您将以相同的方式计算反转次数。整体上(2,1,0)有2个反转(因为2> 1和1> 0),并且在子置换(1,0)中有1个版本的反转(因为1> 0)。因此,这将给出(2,1)作为Lehmer代码。如果我们加上始终存在的零,那么这将成为雷曼代码(2,1,0)。
那么您将如何使用它?每个Lehmer码都有一个以10为底的数字,与之相对应,因为每个数字位置都有一个位置值。在上面的(2,1,0)的情况下,我们有2 * 2! + 1 * 1! + 0 * 0! = 4 + 1 + 0 =5。现在,您可以选择一个随机数,例如5,并生成Lehmer码,然后生成特定的排列而无需全部生成。
这是我不久前写的一些代码。它将Lehmer代码称为radix
,因此不会造成混淆。来自我的util repository on GitHub。
/**
* Given a factoradic index, this function computes the radix form of the
* index. That is, it converts the base 10 input index into a non-constant
* factorial base number.
*/
long int factoradic_radix_index_long( long int dim_in, long int idx_in, long int *rad_out )
{
long int i,fct,div,rem;
rem = idx_in;
for(i=dim_in-1;i>=0;i--)
{
fct = factorial( i );
div = rem / fct;
rem = rem % fct;
rad_out[dim_in-1-i] = div;
}
}
要了解如何从基数向量(Lehmer代码)中获得实际排列,下面是一个示例,它完成了从10进制排列索引到排列的整个转换。
long int factoradic_vector_long( long int idx_in, long int dim_in, long int *vec_out )
{
long int i,j,k,rad[dim_in];
int fnd[dim_in];
for(i=0;i<dim_in;i++)
fnd[i] = 0;
factoradic_radix_index_long( dim_in, idx_in, rad );
for(i=0;i<dim_in;i++)
{
for(j=0,k=0;j<dim_in;j++)
{
if( fnd[j] == 0 )
++k;
if( k - 1 >= rad[i] )
break;
}
fnd[j] = 1;
vec_out[i] = j;
}
return 0;
}
答案 5 :(得分:0)
也许这不是那么有效,但它允许处理给定列表的任意数量的随机排列。
import numpy as np
from math import factorial
for i in range(factorial(len(biglist))):
permut = np.random.permutation(biglist).tolist()
...