如何在不使用循环或理解的情况下仅对数组中的正整数进行平方和求和?



这是我的数组:

[3, -1, 1, 14]

我只想对正元素进行平方并将它们相加,而无需使用任何循环或列表/集合/字典理解。但是,可以使用标准库包。

注意:-列表中的元素可以在 -100 到 +100 之间肆虐

我认为递归可用于在列表中移动,但它的效率会大大降低。当 Python 达到系统递归限制(默认为 1000)时,它也可能在长列表上失败。

列表推导可以看作是接受mapfilterreduce等函数的函数的句法糖。例如:

[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_1x_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

你有它。(不过,我仍然希望有一个代数解决方案,以避免过滤列表。

最新更新