2013-03-26 93 views
5

我需要一个Python函数iterate(f, x)创建一个迭代器返回值x,f(x),f(f(x)),f(f(f(x)))等(如,例如,Clojure's iterate)。首先,我想知道:这是否已经存在于标准库的某个地方,我只是想念它?当然,这是很容易与发电机来实现:使用递归函数itertools

def iterate(f, x): 
    while True: 
     yield x 
     x = f(x) 

只是出于好奇:有没有在Python,例如做这一个功能更强大的方式与一些itertools或functools魔术?

在Python 3.3这会工作

def iterate(f, x): 
    return accumulate(repeat(x), lambda acc, _ : f(acc)) 

,但看起来像一个虐待我。我能更好地做到这一点吗?

+3

我会说'累加()'版本就好了。 *两个*版本都很好。 – 2013-03-26 12:07:15

+1

对于'accumulate()'版本,我真的觉得很奇怪,因为对于计算来说,x只需要* once *作为种子,所以需要'repeat(x)'或类似的东西。 – embee 2013-03-26 12:36:03

+0

@embee现在你提到它了,我也觉得很奇怪。作为第一个解决方案最好的问题 – jamylak 2013-03-26 12:38:54

回答

4

itertools似乎没有什么能够做到你想要的,但itertools是一个深藏宝箱,所以我可能错过了一些东西。

您的生成器代码看起来不错。我不知道你为什么要用积累来写它,除非你打了一场荒谬的高尔夫比赛,或者你想让Haskell势不可挡。编写你的函数,使其可读,可理解和可维护。不需要太聪明。

+0

你是对的,在写这篇文章之前,我甚至都没有想过这个奇怪的“累积”版本。我真的很想知道我是否错过了使用itertools的一个很好,简洁的方法。 我发现自己将函数转换为迭代器(像这里或[itertools recipes]中的'tabulate'示例(http:// docs。python.org/2/library/itertools.html#recipes)时不时想知道什么是最Python的方式来做到这一点。 – embee 2013-03-26 12:26:03

3

您可以使用anamorphism(或展开)来简化iterate的定义,并只使用一个起始值。这是我曾经用过的实现,基于一个相当知名的paper

def ana(build, predicate): 
    def h(x): 
     if predicate(x): 
      return 
     else: 
      a, b = build(x) 
      yield a 
      for i in h(b): 
       yield i 
      # with newer syntax: 
      # yield from h(b) 
    return h 

实现iterateana则是这样的:

def iterate(f, x): 
    return ana(lambda x: (x, f(x)), lambda _: False)(x) 

没有itertools,虽然...我同意这不是最可读的变体。事实上,它相当神秘。


更新:有一个更简单的版本,它甚至看起来相当不错。它采取了从here

def unfold(f, x): 
    while True: 
     w, x = f(x) 
     yield w 

而且,让你:

def iterate(f, x): 
    return unfold(lambda y: (y, f(y)), x) 
+0

我喜欢这个。有趣的是,这个'unfold'的构造与我原来的'iterate'生成器完全一样,但是获得了全新的抽象层次和通用性,因为f现在返回对而不是单个值。尼斯。 – embee 2013-03-27 19:11:10