Как выполнять поэлементные арифметические операции (например, сложение, вычитание, умножение) двух списков одинаковой формы с произвольными вложениями

Я хочу выполнять поэлементные математические операции (например, суммирование, умножение ...) над двумя списками Python, содержащими числа, или несколькими вложенными списками, которые могут снова содержать числа или списки и так далее.

При выполнении операции формы двух списков равны. Кроме того, результат должен иметь ту же форму, что и два входных списка.

Форма может отличаться:

  1. длина,

  2. ширина (т.е. количество вложений),

  3. порядок (например, списки начинаются с номера, за которым следует вложенный список, но также может быть так, что он начинается с вложенного списка, за которым следуют числа).

Форма меняется произвольно каждый раз, когда я хочу выполнить математическую операцию.

Как я могу выполнять математические операции со списками произвольной формы?

В прошлом я реализовал индивидуальный фрагмент кода для каждой формы, аналогичный 1, 2, 3, 4, 5, 6, 7, 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() - это заполнители для библиотечных функций, которые я ищу.


person R3n3    schedule 22.08.2019    source источник
comment
Как вы справляетесь с ситуацией, когда формы не совпадают?   -  person wundermahn    schedule 22.08.2019
comment
Форма двух списков всегда одинакова при выполнении арифметической операции. Единственный случай, который я могу придумать, для которого арифметическая операция в общем случае имеет смысл, будет, если один из двух списков будет / содержать один скаляр .   -  person R3n3    schedule 22.08.2019


Ответы (4)


Вот решение, которое я придумал

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]]

Итак, a и b - это ваши списки, а f - это функция, которую вы хотите применить, как видите, я написал простую функцию для добавления целых чисел

Вы можете написать свои собственные лямбды или просто использовать модуль operator.

person dangee1705    schedule 22.08.2019
comment
Мне нравится этот, потому что он более чистый для вызова функции + более универсальный с лямбдой. Хотя «и», похоже, не нужны (отметьте только один), так как он сломается независимо от того, что, если список имеет неправильный формат. - person Chrismon Chin; 22.08.2019
comment
Вы совершенно правы, я просто добавил and для полноты картины :) - person dangee1705; 22.08.2019

Он не совсем использует встроенный модуль 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]
person Paul M.    schedule 22.08.2019

Не уверен насчет какой-либо библиотеки, в которой есть встроенный метод, но использовать его будет не быстрее, чем создать его самостоятельно

пример, который не является производственным кодом, но показывает простой способ сделать это:

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, '+')
person Chrismon Chin    schedule 22.08.2019

Я даю код решения, например, один и три, но это решение полностью зависит от вашего списка, то есть от того, сколько списков у вас внутри списка, потому что я использую цикл 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))
person Sarvesh    schedule 22.08.2019