2017-10-19 67 views
1

我遇到了一个问题,我需要识别在索引位置上找到的元素,而且反过来也就是从一系列元素的唯一组合中识别索引位置列表。可逆笛卡尔产品元素/索引转换函数

我已经写了下面的代码执行任务相当不错:

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] 

例如

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] 

将与一些question-返回值的独特结合,提供的索引整数(尽管在我的脑海中记下该列表中有多少实例化在内存中 - 但是,现在并不一定非常重要)。

我在问的是,itertools似乎已经考虑到了这些类型的问题 - 是否存在与itertools.product函数同样整齐的单行反转。 ['A','Q','Y']将返回一个描述该组合在笛卡儿积中的位置的整数,例如,如果将该整数送入itertools.product函数将返回原始组合?

回答

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) 
+0

奇妙的答案,并已经测试了12个维度,我假设进一步扩展的潜力是c在感性上(如果不是实际上)无限 - 谢谢!有时会令人惊喜和喜悦,这是其中的一种。还要感谢'香草'的代码 - 我还没有在这个深度处理广播(?),现在要完全掌握它,但是又要爱上优雅。谢谢。 –

+0

@TomKimber是的,如果你在2D数组中进行传输,那么将会有NumPy funcs进行广播,其中每一行都是一个组合。所以,它具有性能优势。 – Divakar