这是我的数组:
[3, -1, 1, 14]
我只想对正元素进行平方并将它们相加,而无需使用任何循环或列表/集合/字典理解。但是,可以使用标准库包。
注意:-列表中的元素可以在 -100 到 +100 之间肆虐
我认为递归可用于在列表中移动,但它的效率会大大降低。当 Python 达到系统递归限制(默认为 1000)时,它也可能在长列表上失败。
列表推导可以看作是接受map
、filter
和reduce
等函数的函数的句法糖。例如:
[f(x) for x in xs]
与
list(map(f,xs)
和
[x for x in xs if x>0]
与 相同
list(filter(lambda x:x>0, xs))
Ch3steR在上面的评论中的回答是
sum([x*x if x>0 else 0 for x in xs])
无糖等价物是
xs = [3,-1,1,14]
sum(map(lambda x: x*x if x>0 else 0, xs))
也许为了清楚起见,我们可以删除 lambda:
def square_if_pos(x):
if x>0:
return x*x
if x<=0:
return 0
xs = [3,-1,1,14]
answer = sum(map(square_if_pos, xs))
列表推导的另一个有效答案是
sum([x*x for x in xs if x>0])
其中,没有语法糖相当于
answer = sum(map(square_if_pos,filter(lambda x:x>0, xs))))
或者可能没有那么多括号:
positive_numbers = filter(lambda x: x>0, xs)
positive_squares = map(lambda x: x*x, positive_numbers))
answer = sum(positive_squares)
这两个答案都是等价的,因为用一些零对列表求和或删除这些零是一回事:x+0 == x。也许对于足够长的列表,filter
的解决方案更有效。
你可以从functools中使用reduce:
from functools import reduce
L = [3, -1, 1, 14]
R = reduce(lambda a,b:a+b*b*(b>0),L,0)
print(R) # 206
如果"我只想对正元素进行平方并将它们求和"中的"它们"指的是所有数字(不仅仅是平方),你可以这样写:
R = reduce(lambda a,b:a+b*b**(b>0),L,0)
print(R) # 205
我的意思是它不是最有效的,但它肯定适用于递归:
def sum_and_square(arr, left, right):
if left == right:
if arr[left]>0:
return arr[left]**2
else:
return 0;
mid = int(left + (right-left) / 2)
return sum_and_square(arr, left, mid) + sum_and_square(arr, mid+1, right)
l = [1, 2, -3, -4] * 1000000
sum_and_square(l, 0, len(l)-1)
海报:"我认为递归可以用来在列表中移动,但它的效率会低得多。
实际上,这个问题可以通过使用递归来解决,方法是在每次递归时将列表大小减少一半而不是 1。
def sum_square(x):
if not x:
return 0
if len(x) == 1:
return x[0]*x[0] if x[0] > 0 else 0
# Split array in half, and recurse on two halves
# This limits recursion depth for list of length n to log2(n)
# rather than n
n = len(x) // 2
return sum_square(x[:n]) + sum_square(x[n:])
测试
测试 1:已发布列表
a = [3,-1,1,14]
>>> sum_square(a)
206
测试 2:大列表
from random import randint
# Create large list
a = [randint(-100, 100) for _ in range(10000000)]
>>>sum_square(a)
169445030
正如你被告知不要使用循环和对列表求和一样,除了将流与 python 构建的功能工具一起使用之外,别无他法
使用map(func, *iterables)
计算给定列表的总和
只要你想只对正数进行平方,你的函数就会看起来像
def square(x: int):
if x > 0:
return x * x
else:
return 0
或者你可以用三元运算符将其重写为lambda函数
lambda x: x * x if x > 0 else 0
那么地图函数将看起来像这样
map(lambda x: x * x if x > 0 else 0, arr) # [9, 0, 1, 196]
然后使用sum(*iterable)
函数汇总数组的结果
sum(map(lambda x: x * x if x > 0 else 0, arr))
由于您没有排除生成器表达式:
sum(x * x for x in xs if x > 0)
考虑一下(接下来是数学,^我的意思是幂,这在Python中**
)
x^2 + y^2 == (x+y)^2 - 2*x*y
和
(x+y+z)^2 = ((x+y)+z)^2 = x^2 + 2xy + y^2 + 2*(x+y)*z + z^2
通过归纳可以证明
(x_1 + x_2 + ... + x_n)^2 = 2*x_1 x_2 + 2*(x_1+x_2)*x_3 + ... 2*(x_1+...x_n)*x_n + x_1^2 + ... + x_n^2
那么平方和是总和的平方加上以下两倍
x_1*x_2 + (x_1+x_2)*x_3 + (x_1+... x_n)*x_n
因此,我们需要做的是将部分和x_1
、x_1+x_2
等累积到一个列表中,然后"压缩"列表本身的元素。
让我们再次制作这个 Python。
from itertools import accumulate
def square(x):
return x*x
def plus(x,y):
return x+y
def times(x,y):
return x*y
xs = [3, 1, -1, 14]
xs = list(filter(lambda x: x>0, xs)) # I wish we could avoid this so early
# either this or change square to lambda x:x*x if x>0 else 0
squared_sum = square(sum(xs))
partial_sums = accumulate(xs, plus)
missing_part = 2*sum(map(times, partial_sums, xs[1:]))
answer = squared_sum - missing_part
你有它。(不过,我仍然希望有一个代数解决方案,以避免过滤列表。