reducelist in Python: like reduce but giving the list of intermediate results

瘦欲@ 提交于 2019-12-05 17:36:34

问题


You know the handy reduce function in Python. For example, you could use it to sum up a list like so (pretend there isn't the built-in sum):

reduce(lambda x,y: x+y, [1,2,3,4], 0)

which returns (((0+1)+2)+3)+4 = 10.

Now what if I wanted a list of the intermediate sums? In this case, [1,3,6,10].

Here's an ugly solution. Is there something more pythonic?

def reducelist(f, l, x): 
  out = [x]
  prev = x
  for i in l:
    prev = f(prev, i)
    out.append(prev)
  return out

回答1:


My favourite, if you're recent enough:

Python 3.2.1 (default, Jul 12 2011, 22:22:01) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import itertools
>>> itertools.accumulate([1,2,3,4])
<itertools.accumulate object at 0x1006baad0>
>>> list(itertools.accumulate([1,2,3,4]))
[1, 3, 6, 10]

accumulate also accepts a function argument [even more recent, though-- 3.3]:

>>> list(itertools.accumulate([1,2,3,4], lambda x,y: x+y))
[1, 3, 6, 10]
>>> list(itertools.accumulate([1,2,3,4], lambda x,y: x+y+1))
[1, 4, 8, 13]



回答2:


If you make your solution to a generator it's shorter and it better obeys functional programming style. I would add an default value of 0 for x too:

def reducelist(f, lst, x=0): 
  prev = x
  for i in lst: 
    prev = f(prev, i)
    yield prev

That is definitely more pythonic.




回答3:


Note: Somehow I missed @DSM's answer before I wrote this. Go read and up vote that one instead, I just did. Come back if you want a longer answer.

Python has this, it's called accumulate and it's implemented in the itertools standard library module starting in Python 3.2. The optional second argument, 'func', was added in 3.3.

import itertools

l = [1,2,3,4]
out = itertools.accumulate(l)

In this case out is an iterable. If you need a list, then

out = list(itertools.accumulate(l))

The accumulate() function can be used to generate a running total, or 'accumulated sums'. The default function is addition. We can pass in a function as the second argument:

import itertools
import operator

l = [1,2,3,4]
factorial = itertools.accumulate(l, operator.mul)

Here we pass in operator.mul for multiplication to generate a running product. The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python.

Of course we're not limited to functions defined in the operator module. You can use any function that accepts 2 parameters of the type of the elements in the first parameter. You can get creative, but here I'll do the opposite and explicitly implement the default addition/sum behavior using a lambda:

import itertools

l = [1,2,3,4]
out = itertools.accumulate(l, lambda a, b: a + b)

Finally, since you asked, I think using accumulate is more Pythonic then your looping example.



来源:https://stackoverflow.com/questions/12233788/reducelist-in-python-like-reduce-but-giving-the-list-of-intermediate-results

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!