两个二维列表的逐元素乘积

3

由于这是我要完成的问题,所以我不能使用Numpy或任何其他库函数,我必须定义自己的方法。

我正在编写一个函数,该函数将两个列表(2维)作为参数。该函数应计算两个列表的逐元素乘积,并将其存储在第三个列表中,并从函数返回此结果列表。 输入列表的示例如下:

列表1:

[[2,3,5,6,7],[5,2,9,3,7]]  

列表2:

[[5,2,9,3,7],[1,3,5,2,2]]

该函数会打印以下列表:
[[10, 6, 45, 18, 49], [5, 6, 45, 6, 14]] 

这是我的代码,但它仅适用于包含2个列表(元素)的列表,就像上面的示例一样,并且对此完美地运行,但我想编辑我的代码,以便无论2-D列表中有多少个列表(元素),它都应打印出其逐元素乘积在一个新的2-D列表中,例如:

[
[2, 5, 6],
[3, 2, 1],
[5, 9, 8]
]

应该返回:

[
[60, 90, 48],
[
30, 45, 24
]
]
[[5,2,9,3,7],[1,3,5,2,2],[1,3,5,2,2]]

或者
[[5,2,9,3,7],[1,3,5,2,2],[1,3,5,2,2],[5,2,9,3,7]]

或者在整个列表中包含的任何数量的列表。

def ElementwiseProduct(l,l2):
    i=0
    newlist=[] #create empty list to put prouct of elements in later
    newlist2=[]
    newlist3=[] #empty list to put both new lists which will have proudcts in them
    while i==0:
        a=0
        while a<len(l[i]):
            prod=l[i][a]*l2[i][a] #corresponding product of lists elements
            newlist.append(prod) #adding the products to new list
            a+=1
        i+=1
    while i==1:
        a=0
        while a<len(l[i]):
            prod=l[i][a]*l2[i][a] #corresponding product of lists elements
            newlist2.append(prod) #adding the products to new list
            a+=1
        i+=1
    newlist3.append(newlist)
    newlist3.append(newlist2)
    print newlist3

#2 dimensional list example
list1=[[2,3,5,6,7],[5,2,9,3,7]] 
list2=[[5,2,9,3,7],[1,3,5,2,2]]  
ElementwiseProduct(list1,list2)

1
你应该在列表推导式中使用zip函数。 - Padraic Cunningham
Moses Koledoye的答案应该可以在不使用Numpy的情况下解决问题。 - R. S. Nikhil Krishna
4个回答

6
你可以在列表解析中对两个列表进行 zip,然后进一步 zip 结果的 子列表,最终将项目相乘:
list2 = [[5,2,9,3,7],[1,3,5,2,2]]
list1 = [[2,3,5,6,7],[5,2,9,3,7]]

result = [[a*b for a, b in zip(i, j)] for i, j in zip(list1, list2)]
print(result)
# [[10, 6, 45, 18, 49], [5, 6, 45, 6, 14]]

如果列表/子列表的元素数量不相同,可以使用itertools.izip_longest生成填充值,例如对于较小的列表可以生成一个空子列表,或者对于较短的子列表可以生成0:

from itertools import izip_longest

list1 = [[2,3,5,6]]
list2 = [[5,2,9,3,7],[1,3,5,2,2]]
result = [[a*b for a, b in izip_longest(i, j, fillvalue=0)] 
               for i, j in izip_longest(list1, list2, fillvalue=[])]
print(result)
# [[10, 6, 45, 18, 0], [0, 0, 0, 0, 0]]

你可以将内部的fillvalue从0更改为1,以返回较长子列表中的元素,而不是同质的0。
参考: 列表推导式

你还可以使用参数扩展来实现 result = [[a*b for a, b in zip(*e)] for e in zip(list1, list2)] - Mad Physicist
@MadPhysicist 看起来更整洁,但需要一些关于如何解包的解释 :) - Moses Koledoye
加入使用 reduceoperator.mul,这个答案就完美了。 - smac89

2
这里有一个函数,可以处理任何类型的可迭代对象,嵌套到任意级别(任意数量的维度,不仅仅是2):
def elementwiseProd(iterA, iterB):
    def multiply(a, b):
        try:
            iter(a)
        except TypeError:
            # You have a number
            return a * b
        return elementwiseProd(a, b)
    return [multiply(*pair) for pair in zip(iterA, iterB)]

这个函数是递归的。对于列表中的每个元素,它都会检查该元素是否可迭代。如果是,则输出元素是一个包含可迭代物品的逐元素乘积的列表。如果不是,则返回数字的乘积。
这个解决方案可以处理混合嵌套类型。这里做出了一些假设,即所有嵌套层级的大小都相同,并且在一个可迭代项中为数字的元素(与嵌套可迭代项相比)在另一个可迭代项中始终为数字。
实际上,这个片段可以扩展到将任何n元函数应用于任何n个可迭代物品:
def elementwiseApply(op, *iters):
    def apply(op, *items):
        try:
            iter(items[0])
        except TypeError:
            return op(*items)
        return elementwiseApply(op, *items)
    return [apply(op, *items) for items in zip(*iters)]

要进行乘法运算,您需要使用operator.mul
from operator import mul
list1=[[2,3,5,6,7], [5,2,9,3,7]] 
list2=[[5,2,9,3,7], [1,3,5,2,2]]
elementwiseApply(mul, list1, list2)

产生
[[10, 6, 45, 18, 49], [5, 6, 45, 6, 14]]

可爱,但我怀疑对于提问者来说可能有些过于高级了。另一方面,它可能会对其他读者有所帮助。 - PM 2Ring
1
@PM2Ring。我写这个代码时,认为要处理任意维度的数组。因为你所说的原因,我保留了它。不要期望它成为被接受的答案,但它是一个有用的例子。 - Mad Physicist

1
在Python中,直接循环遍历列表中的项通常比使用索引间接循环更好。这样做可以使代码更易读,并且更有效率,因为它避免了繁琐的索引算术运算。
以下是如何使用传统的for循环解决您的问题。我们使用内置的zip函数同时迭代两个(或多个)列表。
def elementwise_product(list1,list2):
    result = []
    for seq1, seq2 in zip(list1,list2):
        prods = []
        for u, v in zip(seq1, seq2):
            prods.append(u * v)
        result.append(prods)
    return result

list1=[[2,3,5,6,7], [5,2,9,3,7]] 
list2=[[5,2,9,3,7], [1,3,5,2,2]]

print(elementwise_product(list1,list2))

output

[[10, 6, 45, 18, 49], [5, 6, 45, 6, 14]]

我们可以使用列表推导式来使代码更加简洁。一开始可能会更难阅读,但是通过实践你会逐渐习惯列表推导式。
def elementwise_product(list1,list2):
    return [[u*v for u, v in zip(seq1, seq2)] 
        for seq1, seq2 in zip(list1,list2)]

我喜欢这个答案,因为它解决了OP代码中最基本的问题。对于刚开始学习Python的人来说,这可能是最有帮助的。 - Mad Physicist

-1
你可以使用numpy数组。它们是最佳选择,因为它们在C背景上运行,因此在计算方面更快。
首先,安装numpy。打开终端(如果您在Windows中,则为CMD),输入
pip install numpy

或者,如果在Linux中,使用sudo pip install numpy命令进行安装

然后,继续编写您的代码

import numpy as np

list1=np.array([[2,3,5,6,7],[5,2,9,3,7]]) #2 dimensional list example
list2=np.array([[5,2,9,3,7],[1,3,5,2,2]])

prod = np.multiply(list1,list2)
# or simply, as suggested by Mad Physicist,
prod = list1*list2

希望你不介意导入编辑。看起来OP对Python很新,所以最好明确一些。 - Mad Physicist
1
您还需要安装numpy。根据问题的第一行,OP也被要求编写自己的函数,因此不能使用numpy。我不能使用numpy... - Padraic Cunningham
感谢 @PadraicCunningham 指出。已添加安装指南。Numpy 是一个重要的库,所以我认为他应该尝试一下。 - R. S. Nikhil Krishna
他/她不允许使用numpy或导入任何库。 - Padraic Cunningham
Numpy很棒,当你需要它的时候,但初学Python编程的人需要学习如何处理Python的标准类型和语法。此外,使用Numpy会有显著的开销,因此在处理少量数据时过于浪费。 - PM 2Ring
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接