【问题标题】:How to reduce memory consumption when performing a cartesian product?执行笛卡尔积时如何减少内存消耗?
【发布时间】:2020-03-14 16:22:58
【问题描述】:

给定一个二维矩阵,例如[[a,b,c],[d,e,f]...]],我想对该矩阵进行笛卡尔积,以便确定所有可能的组合。

对于这个特定的约束,当我使用具有 12 个不同子集的二维矩阵时,它使用的内存超过了我所拥有的 16 兆字节的分配内存。每个子集中有三个值,所以我会有 312 种不同的组合。

我使用的笛卡尔积函数是:

def cartesian_iterative(pools):
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    return result

我想知道如何在不使用任何外部库的情况下减少内存消耗。我将使用的示例二维数组是[['G', 'H', 'I'], ['M', 'N', 'O'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['P', 'R', 'S'], ['D', 'E', 'F'], ['M', 'N', 'O'], ['D', 'E', 'F'], ['D', 'E', 'F'], ['M', 'N', 'O'], ['A', 'B', 'C'], ['D', 'E', 'F']]

编辑: 作为参考,可以在此处找到问题陈述的链接Problem Statement。这是可能名称文件的链接Acceptable Names

最终代码:

with open('namenum.in','r') as fin:
    num = str(fin.readline().strip()) #the number being used to determine all combinations

numCount = []
for i in range(len(num)):
    numCount.append(dicti[num[i]]) #creates a 2d array where each number in the initial 'num' has a group of three letters


def cartesian_iterative(pools): #returns the product of a 2d array
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    return result

pos = set() #set of possible names
if len(num) == 12: #only uses more than the allocated memory when the num is 12 digits long.
    '''
    This optimization allows the product to only calculate 2 * 3^6 values, instead of 3**12. This saves a lot of memory
    '''
    rights = cartesian_iterative(numCount[6:])
    for left in cartesian_iterative(numCount[:6]):
        for right in rights:
            a = ''.join(left+right)
            if a in names:
                pos.add(a) #adding name to set
else: #if len(num) < 12, you do not need any other optimizations and can just return normal product 
    for i in cartesian_iterative(numCount):
        a = ''.join(i)
        if a in names:
            pos.add(a)
pos = sorted(pos)


with open('namenum.out','w') as fout: #outputting all possible names
    if len(pos) > 0:
        for i in pos:
            fout.write(i)
            fout.write('\n')
    else:
        fout.write('NONE\n')

【问题讨论】:

  • 似乎itertools.product 是解决问题的最佳选择。它返回一个生成器,因此它是内存友好的。您知道/尝试过吗?
  • 我知道模块/功能,但我希望可以在不使用库的情况下进行优化。
  • itertools 是一个内置库。它经过验证、快速且众所周知(可读)。你为什么不想使用它?
  • 是的,我认为这个问题的答案是“使用itertools.product,如果你出于某种原因不想使用它,复制它的C源代码并编写一个扩展”。跨度>
  • @ggorlen 我猜itertools.product 是代码came from...

标签: python optimization memory cartesian


【解决方案1】:

您可以分别在左右半边使用该功能。那么你将只有 2×36 组合,而不是 312。而且它们的长度只有一半,甚至在某种程度上抵消了该因素 2。

for left in cartesian_iterative(pools[:6]):
    for right in cartesian_iterative(pools[6:]):
        print(left + right)

输出:

['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'D']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'E']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'A', 'F']
['G', 'M', 'D', 'D', 'P', 'D', 'M', 'D', 'D', 'M', 'B', 'D']
...

为了更快,只计算一次正确的组合:

rights = cartesian_iterative(pools[6:])
for left in cartesian_iterative(pools[:6]):
    for right in rights:
        print(left + right)

【讨论】:

  • 有趣的解决方案,但它仍然使用超过分配的 16mb 内存。我使用 USACO 分级机测试了这个解决方案。
  • @Krish 这应该最多占用大约 140 kb。 USACO 问题的链接是什么?
  • 所以 3 和 12 确实是限制。那么我只能猜测你再次收集组合而不是处理它们。
  • 使用的测试用例是463373633623。字典的链接是pastebin.com/rTZAxwAN
  • 我确实收集了所有的组合,然后我检查了它是否在字典集中。也许如果我只是立即检查而不是将其添加到容器中,它将减少内存消耗。
猜你喜欢
  • 2015-07-26
  • 2018-03-09
  • 2017-04-18
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2011-11-11
  • 2019-04-07
  • 2021-05-06
相关资源
最近更新 更多