Умножение между двумя списками

у меня есть 2 списка

a=[[2,3,5],[3,6,2],[1,3,2]]
b=[4,2,1]

я хочу, чтобы результат был:

c=[[8,12,20],[6,12,4],[1,3,2]]

В настоящее время я использую следующий код, но его проблема в том, что время вычисления очень велико, так как количество значений в моем списке очень велико. Первый список списка имеет список 1000, в котором каждый список имеет 10000 значений, а второй список имеет 1000 значений. Поэтому время вычисления является проблемой. Мне нужна новая идея, в которой время вычисления меньше. Настоящий код:

a=[[2,3,5],[3,6,2],[1,3,2]]
b=[4,2,1]
c=[]
s=0
for i in b:
    c1=[]
    t=0
    s=s+1
    for j in a:
        t=t+1
        for k in j:
            if t==s:
                m=i*k
                c1.append(m)
    c.append(c1)
print(c)

person Shubham Sharda    schedule 23.07.2015    source источник
comment
Вы ждете Python 3.5 @operator   -  person dawg    schedule 23.07.2015


Ответы (3)


Используйте zip() для объединения каждого list:

a=[[2,3,5],[3,6,2],[1,3,2]]
b=[4,2,1]

[[m*n for n in second] for m, second in zip(b,a)]
person TigerhawkT3    schedule 23.07.2015
comment
это самый быстрый из всех упомянутых до сих пор. вы сэкономили мне много времени. время вычислений сократилось с 10 минут до 3-4 секунд. большое спасибо. - person Shubham Sharda; 23.07.2015

Вы можете использовать numpy:

>>> import numpy as np
>>> a=np.array([[2,3,5],[3,6,2],[1,3,2]])
>>> b=np.array([4,2,1])

>>> a*np.vstack(b)
array([[ 8, 12, 20],
       [ 6, 12,  4],
       [ 1,  3,  2]])

Или, как предложил @csunday95 в качестве более оптимизированного способа использования транспонирования вместо vstack :

>>> (a.T*b).T 
array([[ 8, 12, 20],
       [ 6, 12,  4],
       [ 1,  3,  2]])
person kasravnd    schedule 23.07.2015
comment
Обязательно используйте numpy, если вам нужно использовать python для чего-то такого вычислительно дорогого. - person csunday95; 23.07.2015
comment
теперь вычисление занимает около 5-6 секунд, раньше это занимало около 10 минут. Большое спасибо - person Shubham Sharda; 23.07.2015
comment
ЕСЛИ вы хотите сделать свой код более интересным, вы также можете сделать (a.T*b).T - person csunday95; 23.07.2015
comment
@Kasramvd только что сделал время для обоих, (a.T * b). T потребовалось в среднем 0,045 секунды для массива 100 на 100, умноженного на массив длины 100, в то время как метод в ответе занял 0,63849 секунды. - person csunday95; 23.07.2015
comment
Я подозревал, что что-то не так, когда numpy работал медленнее, чем простое понимание для манипулирования такой большой структурой данных. Я не знаю, что делает изменение (никогда не использовал numpy), но это огромный прирост производительности. Хорошая вещь! - person TigerhawkT3; 23.07.2015
comment
@TigerhawkT3 TigerhawkT3 Я думаю, что vstack по-прежнему быстрее, чем родной Python, но я почти уверен, что изменение размеров в numpy намного медленнее, чем транспонирование, поскольку транспонирование не копирует, а просто изменяет правила обхода. - person csunday95; 24.07.2015
comment
@ csunday95 Да, вы правы, изменение размеров не улучшает производительность, но, как сказал TigerhawkT3, понимание списка здесь работает лучше, и я думаю, причина в том, что понимание списка работает в C, как numpy, но транспонирование в numpy и операция * которая фактически применяет некоторые циклы, что требует больше времени для выполнения! - person kasravnd; 24.07.2015
comment
В любом случае, я задал вопрос об этой проблеме title="почему понимание списка намного быстрее, чем numpy для умножения массивов"> stackoverflow.com/questions/31598677/ - person kasravnd; 24.07.2015

Это может быть не быстрее, но это более аккуратный способ сделать это :)

c = []
b_len = len(b)
for i in range(len(a)):
    b_multiplier = b[i%b_len]
    c.append([x*b_multiplier for x in a[i]])

Альтернативный короткий путь. Теперь я действительно правильно прочитал вопрос и понял, что a и b имеют одинаковую длину:

c = [[x*b[i] for x in a[i]] for i in range(len(a))]  
person Peter    schedule 23.07.2015
comment
Когда это возможно, я бы рекомендовал избегать использования range(len(..., а также жестко закодированных магических чисел (там 3). К счастью, i%3 не нужен, и вы можете заменить его только i. Вам также нужно где-то инициализировать c перед добавлением к нему. - person TigerhawkT3; 23.07.2015
comment
Ну, я предполагал, что первые 3 строки все еще будут там, но что не так с range(len()) и «жестко запрограммированными магическими числами»? Мне просто любопытно, потому что я не слышал этого раньше, также я делаю это на python 2.7, поэтому для меня просто i не сработает :) - person Peter; 23.07.2015
comment
range(len(... обычно является артефактом более традиционных языков, в которых не было простого способа перебора элементов последовательности, и поэтому нужно было делать что-то вроде for (int n=0; n++; n<10) {... и использовать этот n в качестве индекса. У Python нет такой проблемы. - person TigerhawkT3; 23.07.2015
comment
Магические числа — это определенные значения, которые могут понадобиться или не измениться позже, но не имеют простого способа измениться. Например, 3 в вашем коде или включение фактического числа ставок налога с продаж в формулу для налогового калькулятора вместо того, чтобы формула обращалась к переменной. Жесткое кодирование значения делает код, который обычно сложнее поддерживать. - person TigerhawkT3; 23.07.2015
comment
Когда i гарантированно меньше 3, i%3 не имеет дополнительного эффекта. Буквально нет необходимости это делать. Ваша версия Python на это не влияет. - person TigerhawkT3; 23.07.2015
comment
Да, спасибо, я как бы забыл, что b не всегда может быть 3 значения. Что касается бита диапазона, я использую его только в том случае, если мне нужно получить доступ к значению индекса, большую часть времени я стараюсь избегать его, если это возможно :) Без % это приведет к ошибкам индекса, если я не ошибаюсь, я был сделать так, чтобы a могло быть любой длины, а не только 3 значения - person Peter; 23.07.2015
comment
Поскольку a и b имеют одинаковую длину, и вы используете range, вы можете просто использовать элемент в этом range. Для этих конкретных a и b i будет начинаться со значения 0, затем 1 в следующем цикле, затем 2 в последнем цикле. Вы можете просто использовать i. - person TigerhawkT3; 23.07.2015
comment
Я могу вас неправильно понять, ха-ха, но разве это не сработает, если a имеет более 3 циклов или если b - это другое количество значений, которые не соответствуют a? ;п - person Peter; 24.07.2015
comment
Почему количество петель, превышающее 3, имеет к этому какое-то отношение? Вы получаете количество петель из длины a. Если бы a и b имели разную длину, вопрос был бы существенно другим (не умножение матриц). Просто попробуйте запустить его без операции модуля (т. е. b_multiplier = b[i]) вместо того, чтобы продолжать настаивать на том, что это не сработает. Я думаю, вы будете удивлены. :) - person TigerhawkT3; 24.07.2015
comment
О, я только что перечитал вопрос и понял, что количество чисел в b соответствует количеству списков в a, я тестировал, предполагая, что a имеет намного больше записей, чем b, но теперь я понял вашу точку зрения; P - person Peter; 24.07.2015