2011-11-09 8 views
2

Ruby Enumerableにちょっとしたユースケースがあります。nilでないときにEnumeration上のブロックの値を返す

result = my_strategies.some_method do |strategy| 
    strategy.get_result 
end 

をsome_method 方法は単なるプレースホルダーですが、この質問の残りの部分の後ろの基礎となっている:私は、次のような何かをしようとしています。

列挙型my_strategiesには、リモートサービスから値を取得するための戦略の順序付きリストが含まれています。

時には、より良い戦略が失敗する場合がありますが、再試行だけでは修正できないことがあります。その場合、戦略はnilを返します。

私はthusly、各ブロックに頼ることによってこれを行う方法を見ることができます:

result = nil 

my_strategies.each do |strategy| 
    result = strategy.get_result 
    if not r.nil? 
     break 
    end 
end 

これは不必要にうるさいようです。私は最初の例ではsome_methodを代用できるメソッドがあるかどうか疑問に思っています。 .any?と似ていますが、trueを返すのではなく、ブロックをtrueにした値を返します。

私がしようとしているものに代わるアプローチも歓迎します。

EDIT:これは私の代わりにそれがなかったときに返される値の成功戦略を、返されたことを除いて

result = my_strategies.find do |strategy| 
    strategy.get_result 
end 

私はコードブロックをしようとしたので、私はもともとこの質問をしました。私はどの戦略が私に価値をもたらしたか気にしない、ただ価値が何であるかを知りたい。あなたは結果を得るまで

答えて

7

あなたの必要性は非常に一般的ですが、残念ながらコアには、このような抽象化はありません。しかし、Facets人は長い時間前にこのギャップを特定し、(Enumerable#map_detect a.k.a)Enumerable#find_yieldを実装:

result = my_strategies.map_detect { |strategy| strategy.get_result } 

それとも単に:result = my_strategies.map_detect(&:get_result)

result = my_strategies.lazy.map(&:get_result).reject(&:nil?).first 
+0

甘い例;) – lucapette

+1

はい。これは、自分が実装したパターンの一種です。私が疑問に思っていたことは、すでにどこかでこの実装が存在するかどうかです。私は自分のバージョンの既存の機能を書いてはいけません。 –

+0

@Ed:いいえ、そのような抽象はありません。私はいくつかの参考文献を追加する答えを編集します。 – tokland

1

あなたは、配列を反復処理するためにEnumerable#findを使用することができます。

result = nil 

my_strategies.find do |strategy| 
    result = strategy.get_result 
end 
+0

実は、今私がつまずいていること'Enumerable#find'ではこれがはるかに優れています! –

+0

私の編集を参照してください。これは、私がfindの意味論を誤解していない限り、返されたいものとは異なる何かを私に与える。 –

+0

私は確信していませんが、私はOPが戦略そのものではなく、get_resultの出力を望んでいると思います。 – tokland

0

(ブロックを使用せずに)これを実行する別のアプローチ:(初期のバージョンはenumerable-lazyを使用するため)のRuby 2.0は、今私たちが書くことができます怠惰enumerablesを実装

result = nil 
num = 0 

while result.nil? 
    result = my_strategies[num].get_result 
    num += 1 
end 
関連する問題