Posted over 3 years ago. Visible to the public. Repeats.

How to iterate over an Enumerable, returning the first truthy result of a block ("map-find")

Ruby has Enumerable.find(&block), which returns the first item in the collection for which the block evaluates to true.

Copy
first_post_with_image = posts.find do |post| post.image end

However, sometimes it's not the item you're interested in, but some value depening on it – e.g. the value the block evaluated to. You could first map the collection and then take the first truthy value, but this way you need to process the whole collection twice:

Copy
first_image_url = posts.map(&:image).find(&:present?).url

If the mapping is a costly operation or has undesirable side effects, you need to do it in a single iteration instead.

Single iteration solution

Copy
first_image_url = posts.find do |post| break post.image.url if post.image.present? end

Explanation

As you know, #find loops through the collection, yielding the block with each item. Calling break with an argument will exit the whole block evaluation, returning whatever argument was given to break.

While the condition (post.image.present?) is false, the block returns nil and #find will try the next item in the collection. If the condition is never true, #find will return nil.

Once an application no longer requires constant development, it needs periodic maintenance for stable and secure operation. makandra offers monthly maintenance contracts that let you focus on your business while we make sure the lights stay on.

Owner of this card:

Avatar
Dominik Schöler
Last edit:
about 2 years ago
by Dominik Schöler
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Dominik Schöler to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more