Перекрестное умножение Python с произвольным количеством списков

#python

Вопрос:

Я не уверен, какой правильный термин здесь используется для умножения, но мне нужно умножить элемент из списка A, например, на каждый элемент в списке B и создать новый список для новых элементов, чтобы общая длина нового списка составляла len(A)*len(B).

В качестве примера

 A = [1,3,5], B=[4,6,8]
 

Мне нужно умножить их вместе, чтобы получить

 C = [4,6,8,12,18,24,20,30,40]
 

Я исследовал это и обнаружил, что в itertools(продукте) есть именно то, что мне нужно, однако это для определенного количества списков, и мне нужно обобщить любое количество списков по запросу пользователя.

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

Например (ввод данных пользователем)

 A = [2,5,8], B= [4,7,3]
 

Большой список будет

 C = [[2,5,8],[4,7,3]]
 

В этом случае в большом списке есть два списка, но в целом это может быть любое количество списков.

Как только в коде появится это, у меня будет

 print([a*b for a,b in itertools.product(C[0],C[1])])
>> [8,14,6,20,35,15,32,56,24]
 

Результат этого именно то, что я хочу, однако в данном случае код написан ровно для двух списков, и мне нужно, чтобы он был обобщен на n списков.

Я думал о создании цикла, чтобы каким-то образом повторить его n раз, но до сих пор мне это не удавалось. Поскольку C может иметь любую длину, то циклу нужен способ узнать, когда он достигнет конца списка. Мне это не нужно для вычисления продукта с n списками одновременно

 print([a0*a1*...*a(n-1) for a0,a1,...,a(n-1) in itertools.product(C[0],C[1],C[2],...C[n-1])])
 

Цикл может умножать два списка одновременно, а затем использовать результат этого умножения против следующего списка в C и так далее до C[n-1].

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

p.s. Я использую numpy, и списки представляют собой массивы.

Ответ №1:

Вы можете передать переменное количество аргументов в itertools.product with * . * является оператором распаковки, который распаковывает список и передает его значения значениям списка в функцию, как если бы они передавались отдельно.

 import itertools
import math

A = [[1, 2], [3, 4], [5, 6]]

result = list(map(math.prod, itertools.product(*A)))
print(result)
 

Результат:

 [15, 18, 20, 24, 30, 36, 40, 48]
 

Вы можете найти много объяснений в Интернете об * операторе. Короче говоря, если вы вызовете функцию типа f(*lst) , она будет примерно эквивалентна f(lst[0], lst[1], ..., lst[len(lst) - 1]) . Таким образом, это избавит вас от необходимости знать длину списка.

Редактировать: Я только что понял, что math.prod это функция 3.8 . Если вы используете более старую версию Python, вы можете заменить ее эквивалентом numpy, np.prod .

Ответ №2:

Вы можете использовать функцию сокращения, предназначенную именно для этих типов операций, которая основана на рекурсии и накоплении. Я привожу вам пример с примитивной функцией, чтобы вы могли лучше понять ее функциональность:

 lists = [
    [4, 6, 8],
    [1, 3, 5]
]


def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    for element in it:
        value = function(value, element)
    return value


def cmp(a, b):
    for x in a:
        for y in b:
            yield x*y


summed = list(reduce(cmp, lists))

# OUTPUT

[4, 12, 20, 6, 18, 30, 8, 24, 40]
 

В случае, если вам нужно его отсортировать, просто воспользуйтесь функцией sort ().