Ruby – Array.find,但返回块的值

我有一个数组,我想要第一个块的结果返回一个truthy值(又名,不是nil)。 问题在于,在我的实际使用案例中,测试有副作用(我实际上是在一组队列上迭代,然后从顶部弹出),所以我不需要在第一次成功之后评估该块。

a,b,c = [1,2,3] [a,b,c].first_but_value{ |i| (i + 1) == 2 } == 2 a == 2 b == 2 c == 3 

有任何想法吗?

 [1, 2, 3].detect { |i| i += 1; break i if i == 2 } # => 2 [1, 2, 3].detect { |i| i += 1; break i if i == 10 } # => nil 

break是丑陋的= P

如果你想要一个function方法,你想要一个懒惰的地图:

 [nil, 1, 2, 3].lazy.map{|i| i && i.to_s}.find &:itself # => "1" 

如果你不相信它不是在整个arrays中迭代,只需打印出来并看到:

 [nil, 1, 2, 3].lazy.map{|i| (pi) && i.to_s}.find &:itself # nil # 1 # => "1" 

用块替换i.to_s

这是你想要做的吗?

 a, b, c = 1, 2, 3 binding.tap { |b| break b.local_variable_get [ :a, :b, :c ].find { |sym| b.local_variable_set( sym, b.local_variable_get( sym ) + 1 ) == 2 } } #=> 2 a #=> 2 b #=> 2 c #=> 3 

find_yield做你想要的,查看带有许多核心扩展的ruby facets,特别是find_yield Enumberable方法: https : //github.com/rubyworks/facets/blob/master/lib/core/facets/enumerable/find_yield.rb

这是我的看法,这是否更接近您的实际用例? 注意b的内容是3而不是2因为在b上也调用了my_test_with_side_effect

 class MyQueue def initialize(j) @j = j end def my_test_with_side_effect (@j+=1) == 2 end end (a,b,c) = [MyQueue.new(1),MyQueue.new(2),MyQueue.new(3)] [a,b,c].each { |i| break i unless i.my_test_with_side_effect } => # a => # b => # c => # 

我怀疑有办法做到这一点。 问题是Ruby在块中创建了一个闭包,而变量i在它本地。 执行i+=1可以扩展到i = i + 1 ,这会在块的范围内创建一个新的变量i ,并且不会修改任何a,b,c变量中的值。