Sorry this page looks weird. It was automatically migrated from my old blog, which had a different layout and different CSS.

Map Detect

Recently I wanted to pass each entry in an array to a block, and return the first non-false block result. This is the converse of Enumberable#detect, where you pass each entry to a block and return the first entry for which the block result is not false.

Put another way, it’s a lazy map plus detect.

Ruby does not evaluate its enumerations lazily, so this is how to do it:

module Enumerable
  def map_detect
    self.each do |item|
      if result = (yield item)
        return result
      end
    end
    nil
  end
end

Credit: Arnau Sánchez Sala

Example

I want to search across several models for a particular reference number (by scanning a barcode, as it happens). The map_detect snippet above lets me write:

def search_by_code(code)
  garment = [ Shirt Jacket Suit Coat ].map_detect { |klass| klass.find_by_code code }
  # ...
end

Andrew Stewart • 19 September 2011 • Ruby
You can reach me by email or on Twitter.