使用Python对包含“None”的列表进行求和

56

我的问题基本上是这样的:如果你有一个包含 'None' 的列表,你该如何尝试检索出列表的总和。下面是我尝试过的一个示例,但它不起作用,我得到了错误:TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'。谢谢

def sumImport(self):
    my_list = [[1,2,3,None],[1,2,3],[1,1],[1,1,2,2]]
    k = sum(chain.from_iterable(my_list))
    return k
8个回答

73

你可以使用filter函数。

>>> sum(filter(None, [1,2,3,None]))
6

从评论中更新

通常情况下,filter 的使用方式是 filter(func, iterable),但当第一个参数传递 None 时,这是一种特殊情况,可以在Python文档中找到相关描述。引用文档中的描述:

如果函数是 None,则假定为恒等函数(即删除所有可迭代对象中值为 false 的元素)。


2
也许对于不了解的人(像我一样)有用的是要提到:“如果functionNone,则假定为恒等函数,即删除iterable中所有为假的元素。”(文档 - Felix Kling
1
@FelixKling 我更新了我的答案,并附上了文档链接。 - Alexey Kachayev
4
请注意,每个“假”的元素都将被过滤掉:list(filter(None, [0, 1, 2, None, False, True])) # =[1, 2, True] - Heretron

14

使用filter在求和之前删除None(和零)元素:

>>> k = sum(filter(None, chain.from_iterable(my_list)))
>>> k
20
为了了解这个是如何工作的,查看filter函数的文档:

filter(function, iterable)

根据function返回True的元素构建一个列表。 iterable可以是序列、支持迭代的容器或迭代器。如果iterable是字符串或元组,则结果也具有该类型;否则,它始终是列表。如果省略了function参数,则假定为恒等函数,即删除所有为false的可迭代对象中的元素。

请注意,如果function不是None,则filter(function, iterable)等价于[item for item in iterable if function(item)],如果functionNone,则等价于[item for item in iterable if item]


谢谢,Mark。这帮了我很多。 - Sam

7
另外一个建议:
from itertools import chain
k = sum(x for x in chain.from_iterable(my_list) if x)

如果您在可迭代对象中传递了某个“false”但仍对总和做出了一些贡献的对象,则会失败。使用if x is None可以解决这个问题[尽管我不知道为什么有人会创建一个结果为“false”但对总和有贡献的对象]。 - Bakuriu
@Bakuriu:不存在任何测试为假但可能对总和有贡献的东西。 - Tim Pietzcker
1
这段代码的作用是:class MyClass(object): def __nonzero__(self):return False def __add__(self, other): return other + 1。因此,可能会存在这样的情况,尽管没有内置类型具有这种“属性”,而且创建这样的对象可能并不真正有用。 - Bakuriu
这需要导入什么吗?:NameError: name 'chain' is not defined - Mausy5043
1
@Mausy5043:糟糕。是的,实际上需要使用 from itertools import chain。请参见 https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable - Tim Pietzcker

5
假设您希望将 None 视为零,一个简单的方法是:
sum(x if x is not None else 0 for x in chain.from_iterable(my_list))

3
既然 0 对总和没有贡献,你可以把 None 值也去掉。 - Martijn Pieters
@MartijnPieters 这个答案对于那些想要给可能包含一些None值的列表中的每个元素添加一个值的人很有帮助。 - virtualxtc
1
@virtualxtc:是的,但‘if x不是None’测试应该到循环的末尾,以过滤掉元素而不是将另一个0添加到总和中:sum(x for x in chain.from_iterable(my_list) if x is not None)。我并没有说这个答案没有帮助! - Martijn Pieters

3

明确地说,这相当于筛选:

k = sum([x for x in chain.from_iterable(my_list) if x])

那能省去我记忆另一个函数的麻烦。:P

1

您总是可以选择编写您想要的循环:

k = 0
for sublist in my_list:
    for val in sublist:
        if val is not None:
            k += val

但是了解 filter 也绝对不会有坏处。


0

只需使用sum和map:

sum(map(lambda x: x or 0, [1,2,3,None])) 
# 6

0

如果只想要对数字求和,也可以进行类型检查。例如:

test_list = [2,4,6,8.9,9.0,None,False,True,'abc','vv']
sum([x for x in test_list if type(x) is float or type(x) is int])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接