可逆笛卡尔积元素/索引转换函数

时间:2017-10-19 14:05:00

标签: python numpy itertools

我有一个问题,我需要识别在索引位置找到的元素 the Cartesian product of a series of lists但也是相反的,即从一系列列表中的元素的唯一组合中识别索引位置。

我已经编写了以下代码,可以很好地完成任务:

import numpy as np

def index_from_combination(meta_list_shape, index_combination ):
    list_product = np.prod(meta_list_shape)
    m_factor = np.cumprod([[l] for e,l in enumerate([1]+meta_list_shape)])[0:len(meta_list_shape)]
    return np.sum((index_combination)*m_factor,axis=None)


def combination_at_index(meta_list_shape, index ):
    il = len(meta_list_shape)-1
    list_product = np.prod(meta_list_shape)
    assert index < list_product
    m_factor = np.cumprod([[l] for e,l in enumerate([1]+meta_list_shape)])[0:len(meta_list_shape)][::-1]
    idxl = []
    for e,m in enumerate(m_factor):
        if m<=index:
            idxl.append((index//m))
            index = (index%m)
        else:
            idxl.append(0)
    return idxl[::-1]

e.g。

index_from_combination([3,2],[2,1])
>> 5
combination_at_index([3,2],5)
>> [2,1]

其中[3,2]描述了一系列两个列表,一个包含3个元素,另一个包含2个元素。组合[2,1]表示由第一列表中的第三元素(零索引)和第二列表中的第二元素(再次零索引)组成的排列。

...如果有点笨拙(并且,为了节省空间,忽略列表的实际内容,而是使用其他地方用于从这些列表中获取内容的索引 - 这在这里并不重要虽然)。

N.B。重要的是我的职能相互映射,以便:

F(a)==b   and G(b)==a  

即。它们是彼此相反的。

从链接的问题来看,事实证明我可以用一行代替第二个函数:

list(itertools.product(['A','B','C'],['P','Q','R'],['X','Y']))[index]

这将返回所提供的索引整数的唯一值组合(尽管在我的脑海中有一些问号,关于该列表在内存中实例化了多少 - 但同样,现在不一定重要)。

我要问的是,itertools似乎是在考虑到这些类型的问题的基础上构建的 - 与itertools.product函数有一个同样简洁的单行反转,给定一个组合,例如['A','Q','Y']将返回一个整数,描述该组合在笛卡尔积中的位置,这样,如果将此整数输入itertools.product函数,它将返回原始组合吗?

1 个答案:

答案 0 :(得分:2)

将这些组合想象成二维X-Y坐标并使用subscript to linear-index conversion和反之亦然。因此,使用NumPy的内置插件np.ravel_multi_index获取线性索引,并使用np.unravel_index下标索引,分别成为index_from_combinationcombination_at_index

这是一个简单的翻译,并且不会产生任何组合,所以应该是轻而易举的。

示例运行以使事情更清晰 -

In [861]: np.ravel_multi_index((2,1),(3,2))
Out[861]: 5

In [862]: np.unravel_index(5, (3,2))
Out[862]: (2, 1)

如果您因某些原因不想要NumPy依赖项,那么数学很容易实现 -

def index_from_combination(a, b):
    return b[0]*a[1] + b[1]

def combination_at_index(a, b):
    d = b//a[1]
    r = b - a[1]*d
    return d, r

示例运行 -

In [881]: index_from_combination([3,2],[2,1])
Out[881]: 5

In [882]: combination_at_index([3,2],5)
Out[882]: (2, 1)