56

Basically my question is say you have an list containing 'None' how would you try retrieving the sum of the list. Below is an example I tried which doesn't work and I get the error: TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'. Thanks

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
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
Sam
  • 1,479
  • 3
  • 14
  • 16

8 Answers8

72

You can use filter function

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

Updated from comments

Typically filter usage is filter(func, iterable), but passing None as first argument is a special case, described in Python docs. Quoting:

If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed.

Alexey Kachayev
  • 6,106
  • 27
  • 24
  • 2
    Maybe useful to mention for people who don't know (like me): *"If `function` is `None`, the identity function is assumed, that is, all elements of `iterable` that are false are removed."* ([docs](http://docs.python.org/library/functions.html#filter)) – Felix Kling Sep 01 '12 at 17:38
  • 1
    @FelixKling Updated my answer with doc link. – Alexey Kachayev Sep 01 '12 at 17:41
  • 4
    Notice every falsy element will be filtered : `list(filter(None, [0, 1, 2, None, False, True])) # = [1, 2, True]` – Heretron Feb 27 '19 at 09:40
14

Remove None (and zero) elements before summing by using filter:

>>> k = sum(filter(None, chain.from_iterable(my_list)))
>>> k
20

To see why this works, see the documentation for filter:

filter(function, iterable)

Construct a list from those elements of iterable for which function returns true. iterable may be either a sequence, a container which supports iteration, or an iterator. If iterable is a string or a tuple, the result also has that type; otherwise it is always a list. If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed.

Note that filter(function, iterable) is equivalent to [item for item in iterable if function(item)] if function is not None and [item for item in iterable if item] if function is None.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
7

Another suggestion:

from itertools import chain
k = sum(x for x in chain.from_iterable(my_list) if x)
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • It would fail if you pass in the iterable some object which is "false" but nonetheless give some contribute to the sum. Using `if x is None` would solve this[even though I don't know why someone would create an object that results "false" but gives a contribute to a sum]. – Bakuriu Sep 01 '12 at 19:01
  • @Bakuriu: There doesn't exist *anything* that tests false but could contribute to a sum. – Tim Pietzcker Sep 01 '12 at 22:01
  • 1
    This would do that: `class MyClass(object): def __nonzero__(self):return False def __add__(self, other): return other + 1`. So there may exist something like this, even though no built-in type has this "property", and anyway creating such an object is probably not really useful. – Bakuriu Sep 03 '12 at 05:33
  • Does this require importing something? : `NameError: name 'chain' is not defined` – Mausy5043 Oct 25 '15 at 08:33
  • 1
    @Mausy5043: Oops. Yes, actually: `from itertools import chain` is required. See https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable – Tim Pietzcker Oct 25 '15 at 12:28
5

Assuming you want to treat None as zero, a simple way is

sum(x if x is not None else 0 for x in chain.from_iterable(my_list))
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • 3
    You may as well drop the `None` values, since `0` is not going to contribute to the total sum either. – Martijn Pieters Sep 01 '12 at 17:38
  • @MartijnPieters This answer is helpful for those that want to add a value to each element in a list that may contain some `None` values. – virtualxtc Aug 13 '18 at 19:52
  • 1
    @virtualxtc: yes, but the `if x is not None` test should go to the *end* of the loop, to filter out elements rather than add another `0` to the sum: `sum(x for x in chain.from_iterable(my_list) if x is not None)`. I didn't say the answer was not helpful! – Martijn Pieters Aug 13 '18 at 20:12
3

Explicitly, this is equivalent to filter:

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

That saves me from remembering another function. :P

Taro Sato
  • 1,444
  • 1
  • 15
  • 19
1

You always have the option of just writing the loop you want:

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

But it certainly doesn’t hurt to know about filter either.

Jason Orendorff
  • 42,793
  • 6
  • 62
  • 96
0

Just using sum and map:

sum(map(lambda x: x or 0, [1,2,3,None])) 
# 6
TigerTV.ru
  • 1,058
  • 2
  • 16
  • 34
0

In case one's intention is to sum up the numbers only, one can also do type checking. For example:

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])