如何对具有任意嵌套的两个形状相同的列表执行逐元素算术运算(例如加、减、乘)

How to perform element-wise arithmetic operations (e.g. add, subtract, multiply) of two equally shaped lists with arbitrary nestings

我想对包含数字的两个 Python 列表或可能再次包含数字或列表等的多个嵌套列表执行逐元素数学运算(例如求和、乘法..)。

两个列表的形状在执行操作时是相等的。此外,结果应该与两个输入列表的形状相同。

形状可能有所不同:

  1. 长度,

  2. 宽度(即嵌套数),

  3. order(例如,列表以数字开头,后跟嵌套列表,但也可能以嵌套列表开头,后跟数字)。

每次我要进行数学运算时,形状任意变化。

如何对任意形状的列表执行数学运算?

过去,我为每个不同的形状实现了一段定制的代码,类似于1, 2, 3, 4, 5, 6, 7, 8, ,但我想知道是否已经有更通用的库形式的解决方案或者这个的参考代码。

例1(求和):

a = [ 1, 2, 3, 4,[ 5, 6, 7, 8]]
b = [10,20,30,40,[50,60,70,80]]
c = elementwiseSUM(a,b)
c

会导致

[11, 22, 33, 44, [55, 66, 77, 88]]

例2(求和):

d = [ 1,[ 2, 3],  4, [ 5, 6, 7], [[ 8], [ 9, 10]]]
e = [10,[20,30], 40, [50,60,70], [[80], [90,100]]]
f = elementwiseSUM(d,e)
f

会导致

[11, [22, 33], 44, [55, 66, 77], [[88], [99, 110]]]

例3(乘法):

g = [[4,2],1,1]
h = [[8,3],1,9]
i = elementwiseMUL(g,h)
i

会导致

[[32, 6], 1, 9]

elementwiseSUM()elementwiseMUL() 是我正在寻找的库函数的占位符。

它并没有完全利用内置的 python 模块(除了 operator),但是像这样的东西怎么样?

def element_wise(list_a, list_b, operator):
    result = []
    assert len(list_a) == len(list_b)
    for a, b in zip(list_a, list_b):
        is_lists = isinstance(a, list) and isinstance(b, list)
        is_ints = isinstance(a, int) and isinstance(b, int)

        if is_lists:
            result.append(element_wise(a, b, operator))
        elif is_ints:
            result.append(operator(a, b))
        else:
            raise ValueError
    return result


def main():

    from operator import add, mul

    list_sum_a = [ 1,  2,  3,  4, [ 5,  6,  7,  8]]
    list_sum_b = [10, 20, 30, 40, [50, 60, 70, 80]]

    list_mul_a = [[4, 2], 1, 1]
    list_mul_b = [[8, 3], 1, 9]

    result_sum = element_wise(list_sum_a, list_sum_b, add)
    result_mul = element_wise(list_mul_a, list_mul_b, mul)

    print(result_sum)
    print(result_mul)

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

输出:

[11, 22, 33, 44, [55, 66, 77, 88]]
[[32, 6], 1, 9]

这是我想出的解决方案

a = [ 1,  2,  3,  4, [ 5,  6,  7,  8]]
b = [10, 20, 30, 40, [50, 60, 70, 80]]

def element_wise(a, b, f):
    return [element_wise(i, j, f) if type(i) == list and type(j) == list else f(i, j) for i, j in zip(a, b)]

c = element_wise(a, b, lambda x, y: x + y) # [11, 22, 33, 44, [55, 66, 77, 88]]

所以 ab 是你的列表, f 是你要应用的函数,正如你所看到的,我写了一个简单的函数来添加整数

您可以编写自己的 lambda 或只使用 operator 模块。

不确定是否有任何具有内置方法的库,但使用一个不会比自己创建一个更快

一个不是任何类型的生产代码但展示了一种简单方法的示例是:

import operator
ops = {
    "+": operator.add,
    "-": operator.sub,
    "*": operator.mul,
    "/": operator.div
}

a = [ 1,[ 2, 3],  4, [ 5, 6, 7], [[ 8], [ 9, 10]]]
b = [10,[20,30], 40, [50,60,70], [[80], [90,100]]]


def foo(x, y, op):
    if type(x) == list:
        return [foo(a, b, op) for a, b in zip(x, y)]
    else:
        return ops[op](x, y)

#Run
print foo(a, b, '+')

我给出了示例一和三的解决方案代码,但是这个解决方案完全取决于您的列表,即列表中有多少列表,因为我正在使用 for 循环,这取决于您的列表。

例1(求和解)

a = [ 1, 2, 3, 4,[ 5, 6, 7, 8]]
b = [10,20,30,40,[50,60,70,80]]   
def elementwiseSUM(a, b):
    pl = []
    cl = []
    for i, j in zip(a, b):
        if type(i) and type(j) != list:
            pl.append(i+j)
        if type(i) and type(j) == list:
            for k, l in zip(i, j):
                cl.append(k+l)
    pl.append(cl)
    return pl
print(elementwiseSUM(a, b))

例2(乘法解)

g = [[4,2],1,1]
h = [[8,3],1,9]
def elementwiseMUL(g, h):
    pl = []
    cl = []
    for i, j in zip(g, h):
        if type(i) and type(j) != list:
            cl.append(i*j)
        if type(i) and type(j) == list:
            for k, l in zip(i, j):
                pl.append(k*l)
    pl.append(cl)
    return pl
print(elementwiseMUL(g, h))