C89
C89

Reputation: 31

Can you put a += operator into a list comprehension?

In python I have a list of strings that are digits. I have a nested for loop to go through it and sum each digit. Is there a way to do this in a list comprehension? Below I have the loop that works and a list comprehension that doesnt work.

num_sum should = 1 + 1 + 8 + 9

number_list = ["1", "18", "9"]

for i in number_list:
       for j in i:
           num_sum += int(j)

# thing = [num_sum += int(j) for i in number_list for j in i]

Upvotes: 1

Views: 1927

Answers (3)

Grismar
Grismar

Reputation: 31354

This is what you're after, I think?

thing = sum(int(n) for n in number_list)

Note: this is effectively a generator, there's no need to put the numbers in a list and then sum them, which is why you don't see [] inside the parentheses of the call to sum().

Or from your example it looks like you actually want to sum the individual digits:

thing = sum(int(d) for n in number_list for d in n)

To answer your question whether you can put a += operator in a list comprehension - you could, but it has no return value itself for all types. += assigns to the expression before the operator, but that assignment itself may or may not have a return value, which would get added to the list you're building in the comprehension. In most cases, that's not what you're after.

@ShadowRanger suggested the solution proposed by @yyforbidden may be faster - it is, in fact:

import random
from timeit import timeit

number_list = [str(random.randint(1, 100)) for _ in range(100)]


def comprehension():
    return sum(int(d) for n in number_list for d in n)


def joined():
    return sum(int(d) for d in ''.join(number_list))


assert comprehension() == joined()

print(timeit(comprehension, number=10000))
print(timeit(joined, number=10000))

Result:

0.4073738
0.3616424

I'd still prefer the comprehension because it more literally states what is going on and readable code is often preferable to performing code - but your needs may differ.

Upvotes: 3

yyforbidden
yyforbidden

Reputation: 159

No you cannot. That's a syntax error.

You can do the following instead:

number_list = ["1", "18", "9"]
num_sum = sum(int(i) for i in ''.join(number_list))

Upvotes: 2

ShadowRanger
ShadowRanger

Reputation: 155546

No, but in Python 3.2+ you can use itertools.accumulate to achieve a similar effect, with chain to flatten your list of strs of digits to an iterable of digits:

from itertools import accumulate, chain

thing = list(accumulate(map(int, chain.from_iterable(number_list))))
num_sum = thing[-1]

or if you don't actually need the list:

num_sum = sum(map(int, chain.from_iterable(number_list)))

In 3.8+, the walrus operator, :=, makes constructing the list with a listcomp possible without accumulate, though you can't use +=, only explicit addition and reassignment, as := doesn't have an expression based += equivalent:

num_sum = 0
things = [(num_sum := num_sum + int(x)) for x in chain.from_iterable(number_list)]

# Chain not strictly necessary; could also do this though it would be a titch slower:
things = [(num_sum := num_sum + int(x)) for num in number_list for x in num]

Upvotes: 0

Related Questions