建议的解决方案忽略了顺序。您将注意到,
expand.grid
在每次迭代中迭代左侧元素,这与Python的
itertools.product
生成器的顺序不同。请注意:
s <- c(1, 2, 3)
n <- 2
do.call("expand.grid", rep(list(s), n))
Var1 Var2
1 1 1
2 2 1
3 3 1
4 1 2 <-- This is the second result using python's product
5 2 2
6 3 2
7 1 3 <-- This is the third result using python's product
8 2 3
9 3 3
与Python解决方案的输出相比:
from itertools import product
c = [1, 2, 3]
n = 2
list(product(c, repeat=n))
[(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3)]
从
itertools.product()文档(强调是我的):
嵌套循环会像读数器一样循环,右侧元素在每次迭代中前进。这种模式创建了词典序,因此如果输入的可迭代对象已排序,则按排序顺序发出乘积元组。
与本答案开头所述的内容(即最左边)进行比较。
幸运的是,在
R
(或任何语言)中生成完全相同的输出相对容易,因为这些只是重复排列。如果您想像
python
那样构建自己的生成器,则如文档所示算法相对简单(即“大致等效于生成器表达式中的嵌套for-loops”)。
有几个包能够以所需的顺序相当高效地生成这些。它们是
gtools
、
arrangements
和
RcppAlgos
*。
以下是所有三个的代码:
gtools::permutations(3, 2, repeats.allowed = T)
arrangements::permutations(3, 2, replace = T)
RcppAlgos::permuteGeneral(3, 2, T)
作为一个好处,这些解决方案比使用
expand.grid
更高效:
system.time(do.call("expand.grid", rep(list(1:7), 8)))
user system elapsed
0.375 0.007 0.382
system.time(RcppAlgos::permuteGeneral(7, 8, T))
user system elapsed
0.057 0.032 0.088
RcppAlgos::permuteCount(7, 8, T)
[1] 5764801
事实上,它们甚至比python
方案更快:
import time
def getTime():
start = time.time()
list(product([1, 2, 3, 4, 5, 6, 7], repeat = 8))
end = time.time()
print(end - start)
getTime()
0.9604620933532715
公正地说,itertools
旨在进行迭代操作,因此具有内存效率,并不是真正意义上的一次性生成所有结果。
*我是RcppAlgos
的作者。
do.call("expand.grid", rep(list(1:3), 2))
的结果如同问题中所示。https://www.rdocumentation.org/packages/rje/versions/1.10.10/topics/powerSet 给出了幂集。t(combn(1:3, 2))
则给出了长度为2的唯一组合。 - G. Grothendieck