我在R 中编写了一个名为RcppAlgos 的包,它具有专门用于此任务的功能。
在@wim 链接到的文章中,您会看到这个过程经常被称为排行正如许多人所指出的,这归结为计数。
在RcppAlgos 包中,有几个用于对各种结构进行排序的排序函数(例如,partitionsRank 用于对整数分区进行排序)。我们将使用comboRank 来完成手头的任务:
library(RcppAlgos)
## Generate random combination from 1:35 of length 4
set.seed(42)
small_random_comb = sort(sample(35, 4))
## Print the combination
small_random_comb
#> [1] 1 4 10 25
## Ranking the combination with comboRank (See ?comboRank for more info).
## N.B. for the ranking functions, we must provide the source vector to rank appropriately
idx = comboRank(small_random_comb, v = 35)
## Remember, R is base 1.
idx
#> [1] 1179
## Generate all combinations to confirm
all_combs = comboGeneral(35, 4)
## Same result
all_combs[idx, ]
#> [1] 1 4 10 25
这些功能也非常有效。它们是用C++ 编写的,并使用gmp 库来处理大量数字。
对于非常大的情况n = 1000000 和r = 10000,它们是否足够高效?
set.seed(97)
large_random_comb = sort(sample(1e6, 1e4))
head(large_random_comb)
#> [1] 76 104 173 608 661 828
tail(large_random_comb)
#> [1] 999684 999731 999732 999759 999824 999878
system.time(lrg_idx <- comboRank(large_random_comb, v = 1e6))
#> user system elapsed
#> 2.036 0.003 2.039
## Let’s not print this number as it is over 20,000 digits
gmp::log10.bigz(lrg_idx)
#> [1] 24318.49
我们可以使用comboSample,当我们使用sampleVec 时,它本质上是“unranks”,用于确认:
check_large_comb = comboSample(1e6, 1e4, sampleVec = lrg_idx)
## Sense comboSample returns a matrix, we must convert to a vector before we compare
identical(as.vector(check_large_comb), large_random_comb)
#> [1] TRUE
如果您在python 中需要这个,我们可以使用rpy2。这是 Jupyter Notebook 的 sn-p:
import rpy2
import random
from itertools import combinations
mylist = range(0,35)
r = 4
combinationslist = list(combinations(mylist, r))
combo = random.choice(combinationslist)
combo
#> Out[25]: (1, 25, 30, 31)
## Convert it to a list to ease the transition to R
lst_combo = list(combo)
%load_ext rpy2.ipython
%%R -i lst_combo
library(RcppAlgos)
comboRank(as.vector(lst_combo), v = 0:34)
#> [1] 11347
## R is base 1, so we subtract 1
combinationslist[11346]
#> Out[40]: (1, 25, 30, 31)