select, reject, find and detect in Ruby

Short answer

select keeps every item where the block is true, reject keeps every item where it is false, and find returns only the first match and stops.

ruby
nums = [4, 8, 15, 16, 23, 42]

nums.select { |n| n.even? }     # [4, 8, 16, 42]
nums.reject { |n| n.even? }     # [15, 23]
nums.find   { |n| n > 10 }      # 15  — a single value, not an array
nums.count  { |n| n > 10 }      # 4

find stops at the first match, so it is much cheaper than select(...).first on a large collection.

#Aliases you will see

  • select is also filter
  • find is also detect
  • reduce is also inject
  • collect is map

Modern style prefers select, find, reduce and map. The aliases exist for historical reasons and turn up in older code.

#Predicate methods read well here

ruby
nums.select(&:even?)
nums.reject(&:zero?)
ruby
nums.any?  { |n| n > 40 }     # true
nums.all?  { |n| n > 0 }      # true
nums.none? { |n| n > 100 }    # true
nums.one?  { |n| n == 42 }    # true

All of them short-circuit — any? stops at the first true, all? at the first false.

#filter_map, when you would chain two

ruby
videos.select { |v| v[:views] > 200 }.map { |v| v[:title] }
videos.filter_map { |v| v[:title] if v[:views] > 200 }

One pass instead of two, and no intermediate array.

#partition, when you want both halves

ruby
popular, quiet = videos.partition { |v| v[:views] > 200 }