包含任何类型项目的列表总和

时间:2018-01-10 17:17:28

标签: python list

我正在学习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

但它不起作用..知道如何做到这一点吗?

3 个答案:

答案 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'

如果您正在寻找效率,我建议在这里做两件事 -

  1. 使用sum表示数值,而不是手动添加循环和
  2. 特殊套管字符串,通过调用str.join来代替它们,而不是总结它们。
  3. 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)代替(因为您可以拥有strunicode个对象)。

    • 调用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