2013-03-26 92 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