我正在尝试将以下循环转换为理解力。
给问题一个input_list = [1, 2, 3, 4, 5]
返回一个列表,其中每个元素都是所有元素的倍数,直到该索引从左到右开始。
因此返回列表将为[1, 2, 6, 24, 120]
。
我有正常循环(并且正在工作):
l2r = list()
for i in range(lst_len):
if i == 0:
l2r.append(lst_num[i])
else:
l2r.append(lst_num[i] * l2r[i-1])
答案 0 :(得分:10)
Python 3.8+解决方案:
lst = [1, 2, 3, 4, 5]
curr = 1
out = [(curr:=curr*v) for v in lst]
print(out)
打印:
[1, 2, 6, 24, 120]
其他解决方案(使用itertools.accumulate
):
from itertools import accumulate
out = [*accumulate(lst, lambda a, b: a*b)]
print(out)
答案 1 :(得分:4)
好吧,您可以这样做(a):
import math
orig = [1, 2, 3, 4, 5]
print([math.prod(orig[:pos]) for pos in range(1, len(orig) + 1)])
这将生成您想要的:
[1, 2, 6, 24, 120]
基本上是通过运行从1
到列表大小的计数器来工作的,在每个点上计算出该位置之前的所有项的乘积:
pos values prod
=== ========= ====
1 1 1
2 1,2 2
3 1,2,3 6
4 1,2,3,4 24
5 1,2,3,4,5 120
(a)请记住,这在运行时效率较低,因为它会计算每个元素的完整产品(而不是缓存最近获得的产品)。您可以在 still 使代码更紧凑(通常是使用列表推导的原因)的同时避免这种情况,例如:
def listToListOfProds(orig):
curr = 1
newList = []
for item in orig:
curr *= item
newList.append(curr)
return newList
print(listToListOfProds([1, 2, 3, 4, 5]))
这显然不是列表理解,但是仍然具有优点,因为它不会使您需要计算的代码杂乱无章。
人们似乎经常不喜欢Python中的函数解决方案,这仅仅是因为该语言表达能力强,并且 诸如列表推导等功能都可以用最少的源代码完成很多工作。
但是,除了函数本身之外,此解决方案还具有单行列表理解的相同优势,因为它占用一行:-)
此外,您可以随时随意更改功能( )(例如,如果在更高版本的Python版本中找到了更好的方法),无需更改调用它的代码中所有不同的位置。
答案 2 :(得分:1)
如果一个迭代取决于较早版本的状态,则不应将此 变成列表理解!
如果目标是单一目标,那么@AndrejKesely的itertools.accumulate()
是一个很好的解决方案(+1),因此有很多解决方案。这是滥用functools.reduce()
的矿井:
from functools import reduce
lst = [1, 2, 3, 4, 5]
print(reduce(lambda x, y: x + [x[-1] * y], lst, [lst.pop(0)]))
但是就列表理解而言,@ AndrejKesely基于分配表达式的解决方案是错误的做法(-1)。这是一种更加独立的理解,不会渗入周围的范围:
lst = [1, 2, 3, 4, 5]
seq = [a.append(a[-1] * b) or a.pop(0) for a in [[lst.pop(0)]] for b in [*lst, 1]]
print(seq)
但这仍然是错误的选择!这是基于similar problem,它也由于错误的原因而被投票。
答案 3 :(得分:1)
递归函数可能会有所帮助。
input_list = [ 1, 2, 3, 4, 5]
def cumprod(ls, i=None):
i = len(ls)-1 if i is None else i
if i == 0:
return 1
return ls[i] * cumprod(ls, i-1)
output_list = [cumprod(input_list, i) for i in range(len(input_list))]
output_list 的值为 [1, 2, 6, 24, 120]
这个方法可以在python3.8中使用海象运算符进行压缩
input_list = [ 1, 2, 3, 4, 5]
def cumprod_inline(ls, i=None):
return 1 if (i := len(ls)-1 if i is None else i) == 0 else ls[i] * cumprod_inline(ls, i-1)
output_list = [cumprod_inline(input_list, i) for i in range(len(input_list))]
output_list 的值为 [1, 2, 6, 24, 120]
因为您打算在列表推导中使用它,所以无需为 i
参数提供默认值。这样就无需检查 i
是否为 None
。
input_list = [ 1, 2, 3, 4, 5]
def cumprod_inline_nodefault(ls, i):
return 1 if i == 0 else ls[i] * cumprod_inline_nodefault(ls, i-1)
output_list = [cumprod_inline_nodefault(input_list, i) for i in range(len(input_list))]
output_list 的值为 [1, 2, 6, 24, 120]
最后,如果你真的想把它保留在一个独立的列表理解行中,你可以按照方法说明 here 使用递归 lambda 调用
input_list = [ 1, 2, 3, 4, 5]
output_list = [(lambda func, x, y: func(func,x,y))(lambda func, ls, i: 1 if i == 0 else ls[i] * func(func, ls, i-1),input_list,i) for i in range(len(input_list))]
output_list 的值为 [1, 2, 6, 24, 120]
它完全是过度设计的,几乎难以辨认,但是嘿!它有效,只是为了好玩。
答案 4 :(得分:0)
对于您的列表,数字可能不是故意的,从1开始是连续的。但是对于故意使用该模式的情况,可以使用内置方法factorial():
from math import factorial
input_list = [1, 2, 3, 4, 5]
l2r = [factorial(i) for i in input_list]
print(l2r)
输出:
[1, 2, 6, 24, 120]
答案 5 :(得分:0)
软件包numpy
具有许多内置的列表理解的快速实现。例如,要获得累积产品:
>>> import numpy as np
>>> np.cumprod([1, 2, 3, 4, 5])
array([ 1, 2, 6, 24, 120])
上面的代码返回一个numpy的数组。如果您不熟悉numpy,则可能更喜欢仅获取普通的python列表:
>>> list(np.cumprod([1, 2, 3, 4, 5]))
[1, 2, 6, 24, 120]
答案 6 :(得分:0)
使用迭代工具和运算符:
from itertools import accumulate
import operator as op
ip_lst = [1,2,3,4,5]
print(list(accumulate(ip_lst, func=op.mul)))