如何从 中一一(不重复)随机选择所有结果itertools.permutations(k)
?或者这个:如何构建随机排列的生成器?类似的东西shuffle(permutations(k))
。我正在使用 Python 2.6。
是的,shuffle(r)
可以使用 if ,但是当提升到 10 以上r = list(permutations(k))
时,这样的列表会占用太多的时间和内存。len(k)
谢谢。
如何从 中一一(不重复)随机选择所有结果itertools.permutations(k)
?或者这个:如何构建随机排列的生成器?类似的东西shuffle(permutations(k))
。我正在使用 Python 2.6。
是的,shuffle(r)
可以使用 if ,但是当提升到 10 以上r = list(permutations(k))
时,这样的列表会占用太多的时间和内存。len(k)
谢谢。
这给出了列表的第 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))
我不知道python是如何实现它的shuffle算法的,但是以下是线性时间的,所以我不明白为什么10的长度这么重要(除非我误解了你的问题?):
对于不同的排列,只需再次运行相同的算法。
如果不编写自己的permutations
.
考虑一下:
permutations
。由于我有一个生成器,如果随机函数在列表末尾附近选择一个条目,那么获得它的唯一方法是遍历所有先前的条目并将它们扔掉,这很糟糕,或者将它们存储在一个列表中,当您有很多选择时,您已经指出这是有问题的。
你是要遍历每一个排列还是只使用几个?如果是后者,那么随机生成每个新排列并将然后存储在set
. 如果您不使用那么多,那么每次发生碰撞时都必须创建新排列的开销将非常低。
有一些算法可以给你排列。您可以在这篇wikipedia article中找到一个在线性时间内工作的。
在 python 中实现它以yield
实现高效的顺序生成。但是,如果您想要不重复的随机选择,您必须生成列表,或者使用Dan发布的算法并记住您已经选择的数字。
您正在寻找的是 Lehmer 指数。Lehmer 索引可以从一个随机整数生成,然后可以转换为一个特定的排列,所有这些都不需要生成一组排列,只有您实际使用的一个排列。
知道你想要 n 个对象的 n 个排列之一,你就知道有 n! 其中。您需要做的就是选择一个介于 0 和 n!-1 之间的数字,然后使用 Lehmer 代码将您的 base-10 索引转换为 Lehmer 代码,然后它将成为一个阶乘基数。这些数字也称为factoradics。
例如,假设您要选择索引为 0、1 和 2 的 3 个对象的特定随机排列。 (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 代码。如果我们添加始终存在的零,那么这将产生 Lehmer 码 (2, 1, 0)。
那么你将如何使用它呢?每个 Lehmer 代码都有一个对应的以 10 为底的数字,因为每个数字位置都有一个位值。在上面的 (2, 1, 0) 的情况下,我们有 2 * 2!+ 1 * 1!+ 0 * 0!= 4 + 1 + 0 = 5。现在您可以选择一个随机数,例如 5,然后生成 Lehmer 码,然后生成特定的排列,而无需全部生成。
这是我不久前写的一些代码来做到这一点。它将 Lehmer 代码称为radix
,以免混淆。这是来自我在 GitHub 上的 util 存储库。
/**
* 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;
}
也许这不是那么有效,但它允许处理给定列表的任意数量的随机排列。
import numpy as np
from math import factorial
for i in range(factorial(len(biglist))):
permut = np.random.permutation(biglist).tolist()
...