Given structured data like [('a', 1), ('b', 3), ('c', 2)]
, how can I sum the integers (here, sum 1 + 3 + 2
to get 6
) using the sum
builtin, in a single expression?
Asked
Active
Viewed 2.3k times
23

Karl Knechtel
- 62,466
- 11
- 102
- 153

David Silva
- 1,939
- 7
- 28
- 60
-
Since OP already knew how to use `sum`, the question is really about how to *get data that can be summed* in a sub-expression passed to `sum`. This boils down to "how do I do something with each element of a list, and collect the results?", which is **extremely** commonly asked, but in **many** different forms. The closest canonical I have so far is [Apply function to each element of a list](/questions/25082410), but I am strongly considering doing a new canonical from scratch. – Karl Knechtel Feb 14 '23 at 17:17
4 Answers
38
sum(n for _, n in structure)
would work.

David Robinson
- 77,383
- 16
- 167
- 187
-
1Surprisingly enough, this is marginally faster than my solution (on python 2.7, OS-X 10.5). -- using a list comprehension increases the speed here by almost 50% (for this small example). – mgilson Aug 31 '12 at 15:38
-
1The only weakness I can think of is that it won't work if one element happens to be `('a', 3, 'extra-data-to-ignore')`, whereas both the explicit index and the `zip` approaches -- even the `reduce` -- generalize a little better that way. I guess in Py3 you could write `sum(b for _, b, *_ in structure)` or something.. – DSM Aug 31 '12 at 15:40
-
@mgilson: took the words out of my mouth, I'd just run the tests myself (Python 2.7, OS-X 10.7). I've read before about how fast tuple unpacking is but it was interesting to see it in action. Might have to do with bound checking in the `x[1]` evaluation. – David Robinson Aug 31 '12 at 15:40
-
FWIW, I'd write this as `sum(n for _, n in structure)` to indicate the first item of each pair wasn't being used. – martineau Aug 31 '12 at 15:41
-
@martineau: I like it. It does look a little obscure, though (like the `_` is a special operator). – David Robinson Aug 31 '12 at 15:42
-
@DavidRobinson -- using `_` for unused elements when unpacking is a pretty well established python convention I think. – mgilson Aug 31 '12 at 15:43
-
2It's a fairly common Python idiom though which many would recognize immediately. – martineau Aug 31 '12 at 15:43
-
@mgilson: I meant for beginners seeing this. If I were a beginner I'd wonder if `_,` were a special operator. – David Robinson Aug 31 '12 at 15:44
-
I've noticed before that `_` for "don't care variables" is a bit controversial. Beginners coming from Prolog or Haskell should be used to it, though :) – Fred Foo Aug 31 '12 at 15:49
-
@DSM: To avoid problems with extra data, one could write `import operator` then `sum(operator.itemgetter(1)(t) for t in structure)`. – martineau Aug 31 '12 at 15:49
-
@DavidRobinson: how can bounds checking matter here? `x, y = xy` does have to check whether `len(xy) == 2`, since otherwise it raises a `ValueError`. – Fred Foo Aug 31 '12 at 15:50
-
3@martineau: you definitely could, but in this case that seems like a *very* roundabout way of writing `t[1]`.. – DSM Aug 31 '12 at 15:51
-
-
For anyone who is new to Python (like me) and is wondering why this works: the sum contains one generator expression (not two arguments, this initially confused me). It is very similar to the answer by mgilson. You can find more about generator expressions here: https://www.geeksforgeeks.org/generator-expressions/ – metatron Nov 09 '22 at 14:44
-
This way is still slightly faster in 3.8; using a list comprehension instead of a generator expression is also still faster, though not by as much in my testing as @mgilson's. (My test data uses 10,000 pairs of (single-character string, single-digit integer).) – Karl Knechtel Feb 14 '23 at 17:26
2
-
1You could use `sum(map(operator.itemgetter(1),structure)` if you really want to avoid the comprehensions ... (but what's the point really?) – mgilson Aug 31 '12 at 15:17
-
1@DavidRobinson -- This new version with `zip` is marginally slower than our answers on python2.7 (OS-X 10.5). – mgilson Aug 31 '12 at 15:47
-
@mgilson in 3.x, `zip` produces an iterable which must be manually unpacked before the `sum`. There aren't any elegant ways to make a single expression out of it (although of course many things can be put on one *line* using `;`) and this approach is *considerably* slower now (unpacking in a list comprehension is nearly twice as fast in my tests). – Karl Knechtel Feb 14 '23 at 17:26
1
Using a functional style, you could do
reduce(lambda x,y:x+y[1], structure,0)
-
1Just a hint, functional programming methods almost got removed from `Python 3` reduce isn't event loaded by default anymore. So list comprehensions should be preferred in this case – user1767754 Dec 03 '17 at 06:56
-