我正在学习python,我们的老师告诉我们编写一个函数,无论其值的类型是什么,都会返回列表的总和。
如果列表是整数,则:sum([1, 4, 5, 6]) = 16
如果列表是字符串,则:sum(['a','b',c']) = 'abc'
该列表也可以由其中的元组和列表组成。
代码需要尽可能简短。我试着写这个:
element = list[0]
for thing in list:
for thingy in thing:
element += thingy
print element
但它不起作用..知道如何做到这一点吗?
答案 0 :(得分:3)
首先,我应该指出您将element
初始化为list[0]
时的错误...您将添加两次。
所以,要解决这个问题,我的第一直觉是从 -
开始def generic_sum(data):
return sum(data, type(data[0])())
但这仅适用于整数和浮点数,列表和元组,以及Counter
个对象(字符串也有__add__
方法,但sum
特殊情况。)
因此,我们需要一个应该适用的更通用的解决方案,希望是任何类型的数据。
这是一个,但您需要注意您的列表元素可以任意嵌套这一事实。我的方法是首先展平您的数据,然后对其元素求和。
一种天真的方法是 -
flat_data = [y for x in data for y in (x if isinstance(x, list) else [x])]
你也可以写成:
flat_data = []
for x in data:
if not isinstance(x, list):
x = [x]
flat_data.extend(x)
然后,
init = flat_data[0]
for v in flat_data[1:]:
init += v
将它放入一个函数中,你有 -
def generic_sum(data):
flat_data = [y for x in data for y in (x if isinstance(x, list) else [x])]
sum_ = flat_data[0] # don't use `sum`, you hide the builtin that way
for v in flat_data[1:]:
sum_ += v
return sum_
以下是一些示例输入的演示 -
>>> generic_sum([[1], 2, 3, [4, 5, 6]])
21
>>> generic_sum(['a', 'b', ['c', 'd']])
'abcd'
如果您正在寻找效率,我建议在这里做两件事 -
sum
表示数值,而不是手动添加循环和str.join
来代替它们,而不是总结它们。
def generic_sum_opt(data):
flat_data = [y for x in data for y in (x if isinstance(x, list) else [x])]
return sum(flat_data) if not isinstance(flat_data[0], str) else ''.join(flat_data)
其功能与上述功能相同,但对于字符串连接应该更有效。
>>> generic_sum_opt([[1], 2, 3, [4, 5, 6]])
21
>>> generic_sum_opt(['a', 'b', ['c', 'd']])
'abcd'
注意强>
对于python2,请使用isinstance(flat_data[0], basestring)
代替(因为您可以拥有str
或unicode
个对象)。
调用str.join
比计算每个字符(二次时间)的计算成本更低(线性时间)。这是字符串不可变的结果。
基准
data = ['a', 'b', ['c', 'd']] * 1000000
%timeit generic_sum(data)
1 loop, best of 3: 1.83 s per loop
%timeit generic_sum_opt(data)
1 loop, best of 3: 1.21 s per loop
在处理数百万个元素时,这两种方法都会跨越一秒。我将此归因于展平步骤。或者,让我们只计算平面数据上的求和代码。
flat_data = ['a', 'b', 'c', 'd'] * 1000000
%%timeit
sum_ = flat_data[0] # don't use `sum`, you hide the builtin that way
for v in flat_data[1:]:
sum_ += v
1 loop, best of 3: 623 ms per loop
%timeit ''.join(flat_data)
10 loops, best of 3: 35.5 ms per loop
这更有意义,更能说明循环中串联字符串的严重低效率。
此外,generic_sum_opt
加快数字总和。
data = [[1], 2, 3, [4, 5, 6]] * 1000000
%timeit generic_sum(data)
1 loop, best of 3: 1.94 s per loop
%timeit generic_sum_opt(data)
1 loop, best of 3: 1.53 s per loop
由于在那里使用sum
,第二个功能肯定更快。
答案 1 :(得分:2)
而不是内置sum
,它需要整个列表或元组中的整数或浮点数,而不是reduce
:
s1 = [1, 4, 5, 6]
s2 = ['a', 'b', 'c']
print(reduce(lambda x, y:x+y, s1))
print(reduce(lambda x, y:x+y, s2))
输出:
16
abc
在Python3中,functools
需要使用reduce
:
from functools import reduce
print(reduce(lambda x, y:x+y, s1))
编辑:为了对嵌套列表的值求和,最好使用递归,因为列表可以是任意深度:
def flatten(l):
return reduce(lambda x, y:x+y, [i if not isinstance(i, list) else flatten(i) for i in l])
print(flatten([['a', 'b', 'c'], ['d', 'e', ['h', ['18', 'dd', 'b']]]]))
输出:
abcdeh18ddb
答案 2 :(得分:0)
您的代码不起作用,因为您连接/汇总第一个元素两次
示例: - 强>
让我们说listy = [1, 2, 3, 4, 5]
&安培; element = listy[0] = 1
现在进行第一次迭代
element = element + thingy (1 + 1)
,因为第一次迭代的东西也指向listy[0]
只需检查列表元素的类型: -
,例如
if isinstance(string, list[0]) :
sum = ""
elif isinstance(int, list[0]):
sum = 0
else :
// raise some error
for i in listy:
sum += i