【问题标题】:Invertable Cartesian Product Elements/Index Translation Function可逆笛卡尔积元素/索引转换函数
【发布时间】:2017-10-19 14:05:00
【问题描述】:

我有一个问题,我需要识别在索引位置找到的元素 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]

例如

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

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

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

注意重要的是我的功能相互镜像,这样:

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 函数将返回原始组合?

【问题讨论】:

    标签: python numpy itertools


    【解决方案1】:

    将这些组合想象成二维 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)
    

    【讨论】:

    • 非常优雅的答案,并在 12 个维度上进行了测试,我认为进一步扩展的潜力在概念上(如果不是实际的话)是无限的 - 谢谢!有时 numpy 既令人惊奇又令人愉悦,这就是其中之一。还要感谢'香草'代码 - 我还没有掌握广播(?)在这个深度,现在完全得到它,但再次,喜欢优雅。谢谢。
    • @TomKimber 是的,如果您输入 2D 数组,其中每一行都是一个组合,将会使用 NumPy 函数进行广播。因此,它具有性能优势。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 2020-07-26
    相关资源
    最近更新 更多