Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby idiom to shortcircuit to return first non-nil using each and map

Tags:

each

ruby

This is the essence of what I'm trying to do but the 'break' doesn't feed right:

needle = nil
haystacks.each do |haystack|
  needle = haystack.look_for_needle()
  break if needle
end

This is shorter, but it will iterate over every haystack (without looking at least) even though it doesn't need to:

needle = nil
haystacks.each do |haystack|
  needle ||= haystack.look_for_needle()
end

This is a one-liner but (I believe) it is not lazy and so it does unnecessary work:

needle = hackstacks.map{|h| h.look_for_needle()}.detect{|x| !x.nil?}

I feel like there should be a one liner, but I'm not sure it would be:

needle = hackstacks.some_find_each_first_detect_lazy_map_thingee {|h| h.look_for_needle()}
like image 622
Rick Avatar asked Aug 29 '16 20:08

Rick


People also ask

How do you check if something is not nil in Ruby?

In Ruby, you can check if an object is nil, just by calling the nil? on the object... even if the object is nil. That's quite logical if you think about it :) Side note : in Ruby, by convention, every method that ends with a question mark is designed to return a boolean (true or false).

How do you get rid of nil in Ruby?

Array#compact () : compact () is a Array class method which returns the array after removing all the 'nil' value elements (if any) from the array. Syntax: Array. compact() Parameter: Array to remove the 'nil' value from. Return: removes all the nil values from the array.

What does &: mean in Ruby?

By prepending & to a symbol you are creating a lambda function that will call method with a name of that symbol on the object you pass into this function.

How does Ruby map work?

The way the map method works in Ruby is, it takes an enumerable object, (i.e. the object you call it on), and a block. Then, for each of the elements in the enumerable, it executes the block, passing it the current element as an argument. The result of evaluating the block is then used to construct the resulting array.


1 Answers

With Ruby 2.x lazy enumerators:

needle = haystacks.lazy.map(&:look_for_needle).reject(&:nil?).first

Or:

needle = haystacks.lazy.map(&:look_for_needle).detect { |needle| !needle.nil? }

Or:

needle = haystacks.lazy.map(&:look_for_needle).detect(&:itself)
like image 177
tokland Avatar answered Oct 10 '22 01:10

tokland