Hacker News new | past | comments | ask | show | jobs | submit login

I've gotten the impression that there are, in a sense - in python, list comprehensions are usually preferred over for-loops in places where you would use map and filter, and the most common use cases for fold/reduce are covered by functions like sum and join. List Comprehensions also tend to be preferred over higher order functions, perhaps for readability, but also, in python 3, the higher order functions return generators, which don't always play nicely with mutable data.

For-loops are still suitable for actions (which mutate state or for some other reason need to be evaluated in order) - you see this in Haskell, too, though, with Control.Monad's forM_ and the like.




After reading this, I got to wondering if I could hijack sum into joining lists. My first attempt didn't work:

  sum([ range(n,n+5) for n in range(5) ])
just gave me "TypeError: unsupported operand type(s) for +: 'int' and 'list'", which didn't make a lot of sense. Where did I pass an 'int' by itself? Well, according to the help, sum takes a second argument: a starting value, which defaults to 0. So, I wondered, what if I were to pass it an empty list...?

  sum([ range(n,n+5) for n in range(5) ], [])
came back with:

  [0, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8]
Holy $#!7

I'd been wanting a way to join multiple lists without having to write another ugly little function! Anyone know if this particular trick is common practice?


I've seen it used for a long time. The only problem with it is the quadratic time complexity: it's equivalent to ((N0 + N1) + N2) + N3 ... so you copy the same elements over and over again as the sum builtin doesn't know to use anything but the + operator to build each element. (I vaguely recall some discussion about making it more efficient on sequences of sequences).

A more efficient version would be: def sumseq(l): r = []; map(r.extend,l); return r

which would also work on any type of sequence as input, even if mixed. A quick test shows the quadratic time complexity being noticeable at about 128 items, where sumseq is 10x as fast and 1751x as fast at 16384 items.


That's actually quite clever.


Thanks, but I got a little update: it won't work on strings.

The help says as much, in fact. Actually, what it says is, "Returns the sum of a sequence of numbers (NOT strings)," which I think is meant to imply it won't parse numbers out of strings, but in theory, sum should be able to concatenate strings as easily as it does lists, with the right start argument. Instead:

  >>> sum([['room315'], ['room2']], [])
  ['room315', 'room2']
but:

  >>> sum(['room315', 'room2'], '')
  TypeError: sum() can't sum strings [use ''.join(seq) instead]
Say, what???

I'm not sure, but I think sum is specifically watching for strings, and throwing a TypeError if it finds one. Otherwise, if it's simply using the + operator internally, as its list-handling behabior seems to imply, it should mash strings together just as happily! Oh, well. The join function is the right one for that job. It just seems a bit of wasted effort, to me.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: