【问题标题】:Itertools combinations find if a combination is divisibleItertools 组合查找组合是否可整除
【发布时间】:2022-10-12 22:27:59
【问题描述】:

给定 r 为 4 的 itertools 组合:

from itertools import combinations

mylist = range(0,35) 
r = 4
combinationslist = list(combinations(mylist, r))

这将输出:

(0, 1, 2, 3)
(0, 1, 2, 4)
(0, 1, 2, 5)
(0, 1, 2, 6)
(0, 1, 2, 7)
(0, 1, 2, 8)
(0, 1, 2, 9)
...
(30, 31, 32, 33)
(30, 31, 32, 34)
(30, 31, 33, 34)
(30, 32, 33, 34)
(31, 32, 33, 34)

我的问题是,如果我们要将列表分成 10 个块,我们能否找到这些块中的第 n 个组合,但不会生成所有组合。或者换句话说,如果该位置可以被 x 整除。

这样做的问题之一是头寸将达到数十亿,并且可能无法得出第 n 个是什么。是否有一种启发式方法可以确定元素的特定组合/序列是否可以被 x 整除

编辑/添加:这个问题的推理是针对列表为 range(0,1000000) 和 r =30000 的情况。然后提供一个组合,求它是否能被 x 整除。自然地,实际的索引会非常大(而且完整的组合太多而无法生成)

【问题讨论】:

  • 换句话说,给定一个排列,找出它会出现在所有排列列表中的哪个位置?当您说组合可整除时,您是什么意思?你是说它的位置吗?
  • 当您说位置时,您是指列表中的索引吗?
  • 当然可以。在您的示例中,有 34*33*32 个条目以 0 开头。有 33*32*31 个条目以 1 开头。因此,前 5 个条目(5,6,7,8)将是条目号 150,750 .这只是数学。
  • 更简单的问题陈述:combinations()ith 位置生成了一个 4 元组。给定(a, b, c, d) 元组,预测索引i。 (然后正如蒂姆·罗伯茨(Tim Roberts)所观察到的,计算“i mod k”是微不足道的。)
  • 这就是捷径的方法。这里没有神奇的单线。您的示例有 110 万个条目,但我们可以通过数百次计算找出条目。

标签: python combinations


【解决方案1】:

看看Combinatorial number system 维基百科文章。

这是我在 Python 中提出的:

from math import comb

def combo_index(combo, n):
    result = 0
    i = 0
    for j, item in enumerate(combo):
        while i < item:
            result += comb(n - i - 1, len(combo) - 1 - j)
            i += 1
        i += 1
    return result

使用您的示例进行演示n=35

>>> len(combinationslist)
52360
>>> combo = random.choice(combinationslist)
>>> combo
(15, 17, 23, 28)
>>> combinationslist[combo_index(combo, 35)]
(15, 17, 23, 28)

这是一种递归方法

def combo_index_r(combo, n):
    k = len(combo)
    if k == 0 or k == n:
        return 0
    if k == 1:
        return combo[0]
    combo = tuple(x - 1 for x in combo)
    if combo[0] == -1:
        return combo_index_r(combo[1:], n - 1)
    return comb(n - 1, k - 1) + combo_index_r(combo, n - 1)

【讨论】:

  • 这是一个可爱的方法!但它不适用于 n=1000000 和 r=10000。我想知道是否有某种方法可以做到这一点?
【解决方案2】:

我在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 = 1000000r = 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多