我想爲Ruby 2的Enumerator :: Lazy類實現一個take_until
方法。它的工作原理與take_while
類似,但當代碼塊返回true時停止迭代。結果應該包括產生的塊匹配的項目。如何在Enumerator :: Lazy方法中停止迭代?
我的問題是我如何表示迭代的結束已達到?使用常規枚舉器時,可以在每個方法中引發StopIteration錯誤,以表示迭代器的結束。但是,這似乎並不適用於懶惰的枚舉:
class Enumerator::Lazy
def take_until
Lazy.new(self) do |yielder, *values|
yielder << values
raise StopIteration if yield *values
end
end
end
(1..Float::INFINITY).lazy.take_until{ |i| i == 5 }.force
我也試圖突破塊無效。 The documentation for Enumerator::Lazy似乎也沒有幫助。
爲什麼使用take_while
不是一個有效的選項。
take_while的主要問題是,從本質上講,它會嘗試評估比您需要的更多的物品。在我的應用程序中,枚舉器不會產生數字,而是通過網絡獲取消息。試圖評估一個不存在的信息(但是?)是一種非常不受歡迎的阻止行爲。這通過以下人爲示例來說明:
enum = Enumerator.new do |y|
5.times do |i|
y << i
end
sleep
end
enum.lazy.take_while{ |i| i < 5 }.force
要從此枚舉器接收前五項,您將需要評估第六個結果。這並不像它那樣懶惰。在我的使用情況下,這是不可取的,因爲這個過程會被阻止。
提供枚舉::懶惰
標準庫包括take
方法,做類似於我想要的東西純Ruby實現的take
。它不會使用塊作爲條件,而是使用數字,但是一旦達到該數字,它就會跳出迭代,而不是評估另外一個項目。繼上面的例子:
enum.lazy.take(5).force
這沒有得到第6項,所以不阻止。問題是標準庫中的版本是用C語言實現的,我似乎無法弄清楚這是如何在純Ruby中實現的。該方法的紅寶石實現將是一個可以接受的答案。
提前致謝!
我討厭問,但不是你只是使用take_while並根據需要修改條件? –
這是一個有效的問題,但我認爲答案是:不,我不能。我的使用案例涉及到一系列的響應,我特別想要在遇到某些情況時對序列進行分隔。 Take_while不會包含匹配的項目本身,而是將順序返回到第一個「未命中」。希望這是有道理的。 –
所以'take_until'會否定一個'take_while',它會做一個額外的'yield next'? – steenslag