计算Python列表中所有数字的乘积

4

假设我有这个列表:

[2,3,5,7] 

我想输出所有乘法组合:

[6,10,14,15,21,35,30,42,105,210]

有没有一个Python一行代码的解决方案?


3
你到目前为止实际上已经尝试过什么了? - jonrsharpe
我已经通过谷歌搜索了很多,但似乎map、reduce等方法并不能立即帮助解决问题。 - Maxime Roussin-Bélanger
1
那不是我的问题的答案。你的代码在哪里?你看过itertools了吗? - jonrsharpe
1
sorted({a * b for (a, b) in combinations(values, 2)}) - Peter Wood
@jonrsharpe 我猜我可以做出长度为列表长度的2个组合? - Maxime Roussin-Bélanger
显示剩余2条评论
3个回答

7
假设您的输出中忘记了70...
使用numpy.prod和itertools.combinations:
假设您的输出中忘记了70...
使用numpy.prod和itertools.combinations:
>>> from numpy import prod
>>> from itertools import combinations
>>> lst = [2,3,5,7]
>>> [prod(x) for i in range(2, len(lst)+1) for x in combinations(lst, i)]
[6, 10, 14, 15, 21, 35, 30, 42, 70, 105, 210]

我不使用numpy软件包,所以我用了:reduce(lambda x, y: x * y, numbers) - Maxime Roussin-Bélanger
这个任务不需要导入 numpy - ᴀʀᴍᴀɴ
@Argman 是的,使用 reduce 而不是 numpy.prod 是可行的,但我认为它更难阅读。如果你不能使用 numpy,reduce(或编写自己的 prod 函数)是有效的备选方案。 - timgeb
@timgeb 我认为reduce不难理解,但也许你是对的。 - ᴀʀᴍᴀɴ
这使用了powerset的特殊情况recipe - Peter Wood
@MaximeRoussin-Bélanger 在您的 reduce 表达式中实际上不需要 lambda 函数,因为它已经存在:reduce(int.__mul__, numbers),但是,当然,您必须确保在此处使用的是整数。 - Thomas Baruchel

2

Itertools是一个很好的选择。作为另一种解决方案,可以使用纯numpy(所有0,1,...,n项的乘积):

from numpy import *
a,n=array(l),len(l)
where(bitwise_and.outer(arange(2**n),2**arange(n))>0,a,1).prod(1)
#array([  1,   2,   3,   6,   5,  10,  15,  30,   7,  14,  21,  42,  35, 70, 105, 210])

在大型列表上速度提高了多达40倍。

一些解释:

bitwise_and.outer(arange(2**n),2**arange(n))

array([[0, 0, 0, 0],
       [1, 0, 0, 0],
       [0, 2, 0, 0],
       [1, 2, 0, 0],
       [0, 0, 4, 0],
       [1, 0, 4, 0],
       [0, 2, 4, 0],
       [1, 2, 4, 0],
       [0, 0, 0, 8],
       [1, 0, 0, 8],
       [0, 2, 0, 8],
       [1, 2, 0, 8],
       [0, 0, 4, 8],
       [1, 0, 4, 8],
       [0, 2, 4, 8],
       [1, 2, 4, 8]], dtype=int32)

where(bitwise_and.outer(arange(2**n),2**arange(n))>0,a,1) 的翻译结果是:

这段代码的作用是将长度为 n 的二进制数列和 2 的 n 次方进行按位与运算,然后判断结果是否大于 0。如果大于 0,则返回 a 数组中对应位置的值,否则返回 1。

array([[1, 1, 1, 1],
       [2, 1, 1, 1],
       [1, 3, 1, 1],
       [2, 3, 1, 1],
       [1, 1, 5, 1],
       [2, 1, 5, 1],
       [1, 3, 5, 1],
       [2, 3, 5, 1],
       [1, 1, 1, 7],
       [2, 1, 1, 7],
       [1, 3, 1, 7],
       [2, 3, 1, 7],
       [1, 1, 5, 7],
       [2, 1, 5, 7],
       [1, 3, 5, 7],
       [2, 3, 5, 7]])

接下来是按行输出prod


不错,但您能否添加一些说明以便理解正在发生的事情吗?如何防止结果中出现值1、2、3、5、7? - timgeb
精简的两行代码解决方案:y=bitwise_and.outer(arange(2**n),2**arange(n))>0; res= where(y,a,1).prod(1)[y.sum(1)>1]。但是限制在2个或更多操作数上在数学上对我来说很棘手(对计算机也是如此...)。 - B. M.

0
一个巧妙的一行代码,不使用任何额外的工具...
假设您的初始列表存储在变量l中:
[ list(l[k] for k in range(len(l))
    if (2**k) & (n+(n+n.bit_length()).bit_length()))
    for n in range(1,2**len(l)-len(l)) ]

返回您所需的组合(只需将初始列表用一些reduce包装以执行乘法本身,但棘手的部分在于其中)。 "gem"是n +(n + n.bit_length())。bit_length(),它将正整数映射到至少包含两个位集(在其二进制展开中),这用于通过确保每次至少取两个成员来选择初始列表的成员。您可以在{{link1:http://oeis.org/A057716}}了解有关此公式的更多信息(我仅适应了先前链接“公式”部分中第一个表达式的Python语法)。

因此,整个答案将是:

[ reduce(int.__mul__,
    (l[k] for k in range(len(l))
        if (2**k) & (n+(n+n.bit_length()).bit_length())))
        for n in range(1,2**len(l)-len(l)) ]

(如果你使用的是Python 3,你需要导入reduce。)


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