我正在寻找一个
的功能1:n
)满足第一个要求,例如permn()
来自包combinat
,permutations()
来自包e1071
,或permutations()
来自包gtools
}。但是,我很肯定,某些软件包还有另一个功能,它也提供了第二个功能。我用了一次,但后来忘记了它的名字。
编辑: “前N”的定义是任意的:函数只需要一个始终遵循的内部枚举方案,并且应该在计算N个排列后中断。
正如Spacedman正确指出的那样,至关重要的是该函数不会计算比实际需要更多的排列(以节省时间)。
编辑 - 解决方案:我记得我正在使用的是numperm()
来自sna
个包。 numperm(4, 7)
给出元素1:4
的第7个排列,对于前N个,必须循环。
答案 0 :(得分:6)
似乎最好的方法是构建一个迭代器,它可以生成排列列表,而不是使用像permn
之类的函数,它可以预先生成整个列表(昂贵的操作)。
寻找构建此类对象的指导的一个好地方是Python标准库中的itertools模块。 Itertools已经部分重新实现为R a package of the same name。
以下是使用R的itertools实现Python生成器的端口的示例,该端口为排列创建迭代器:
require(itertools)
permutations <- function(iterable) {
# Returns permutations of iterable. Based on code given in the documentation
# of the `permutation` function in the Python itertools module:
# http://docs.python.org/library/itertools.html#itertools.permutations
n <- length(iterable)
indicies <- seq(n)
cycles <- rev(indicies)
stop_iteration <- FALSE
nextEl <- function(){
if (stop_iteration){ stop('StopIteration', call. = FALSE) }
if (cycles[1] == 1){ stop_iteration <<- TRUE } # Triggered on last iteration
for (i in rev(seq(n))) {
cycles[i] <<- cycles[i] - 1
if ( cycles[i] == 0 ){
if (i < n){
indicies[i:n] <<- c(indicies[(i+1):n], indicies[i])
}
cycles[i] <<- n - i + 1
}else{
j <- cycles[i]
indicies[c(i, n-j+1)] <<- c(indicies[n-j+1], indicies[i])
return( iterable[indicies] )
}
}
}
# chain is used to return a copy of the original sequence
# before returning permutations.
return( chain(list(iterable), new_iterator(nextElem = nextEl)) )
}
错误引用Knuth:“请注意上述代码中的错误;我只是尝试过它,而不是证明它是正确的。”
对于序列1:10
的前3个排列,permn
为计算不必要的排列付出了沉重的代价:
> system.time( first_three <- permn(1:10)[1:3] )
user system elapsed
134.809 0.439 135.251
> first_three
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 1 2 3 4 5 6 7 8 10 9
[[3]]
[1] 1 2 3 4 5 6 7 10 8 9)
但是,permutations
返回的迭代器只能查询前三个元素,这些元素可以节省大量的计算量:
> system.time( first_three <- as.list(ilimit(permutations(1:10), 3)) )
user system elapsed
0.002 0.000 0.002
> first_three
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 1 2 3 4 5 6 7 8 10 9
[[3]]
[1] 1 2 3 4 5 6 7 9 8 10
Python算法确实以与permn
不同的顺序生成排列。
计算所有排列仍然是可能的:
> system.time( all_perms <- as.list(permutations(1:10)) )
user system elapsed
498.601 0.672 499.284
虽然与permn
相比,Python算法大量使用循环要贵得多。 Python实际上在C中实现了这个算法,它补偿了解释循环的低效率。
代码可用in a gist on GitHub。如果有人有更好的主意,请离开!
答案 1 :(得分:3)
在我的R
/ combinat
版本中,函数permn()
的长度超过了30行。一种方法是复制permn
并将其更改为提前停止。