Enumerable#min_by
Object · Added in v1.8.6 · Updated March 16, 2026 · Enumerable The min_by method returns the element that would be smallest according to the criteria you define in a block. Unlike min which compares elements directly, min_by lets you specify how to compare them.
How It Works
min_by evaluates the block for each element and returns the element that produced the smallest value:
collection.min_by { |element| block_return_value }
The element itself is returned, not the block’s return value.
Basic Usage
Find the shortest string in an array:
words = ["cat", "elephant", "dog", "hippopotamus"]
shortest = words.min_by { |word| word.length }
# => "cat"
Find the youngest person in a collection:
people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 }
]
youngest = people.min_by { |person| person[:age] }
# => {:name=>"Bob", :age=>25}
With Nested Comparisons
When multiple elements produce the same minimum value, min_by returns the first one encountered:
words = ["aa", "bb", "cc", "dd"]
result = words.min_by { |w| w[0] }
# => "aa" (all have the same value, first one wins)
Finding Multiple Minimum Elements
Use min_by with an argument to get multiple minimum elements:
numbers = [5, 2, 8, 1, 9, 3, 7, 4, 6]
smallest_three = numbers.min_by(3) { |n| n }
# => [1, 2, 3]
This is useful for finding top performers by a specific metric:
products = [
{ name: "Laptop", price: 999 },
{ name: "Phone", price: 699 },
{ name: "Tablet", price: 449 },
{ name: "Watch", price: 299 },
{ name: "Headphones", price: 199 }
]
cheapest_three = products.min_by(3) { |p| p[:price] }
# => [{:name=>"Headphones", :price=>199}, {:name=>"Watch", :price=>299}, {:name=>"Tablet", :price=>449}]
With Arrays of Arrays
pairs = [[1, 5], [3, 2], [2, 8], [4, 1]]
# Find pair with smallest first element
by_first = pairs.min_by { |pair| pair[0] }
# => [1, 5]
# Find pair with smallest second element
by_second = pairs.min_by { |pair| pair[1] }
# => [4, 1]
Practical Examples
Finding the Shortest Method Name
methods = [:to_s, :inspect, :class, :object_id, :nil?]
shortest = methods.min_by { |m| m.to_s.length }
# => :nil? (4 characters)
Finding the Cheapest Shipping Option
shipping_options = [
{ carrier: "USPS", weight: 5, distance: 100 },
{ carrier: "FedEx", weight: 5, distance: 50 },
{ carrier: "UPS", weight: 5, distance: 75 }
]
cheapest = shipping_options.min_by { |opt| opt[:weight] * opt[:distance] * 0.5 }
# => {:carrier=>"FedEx", :weight=>5, :distance=>50}
Finding the Nearest Location
current_location = { x: 10, y: 10 }
locations = [
{ name: "Office", x: 5, y: 5 },
{ name: "Home", x: 15, y: 15 },
{ name: "Store", x: 8, y: 12 }
]
nearest = locations.min_by { |loc|
(loc[:x] - current_location[:x]).abs + (loc[:y] - current_location[:y]).abs
}
# => {:name=>"Office", :x=>5, :y=>5}
Comparison with min
| Method | Use When |
|---|---|
min | You want natural/built-in comparison |
min_by | You need custom comparison logic |
numbers = [5, 2, 8, 1, 9]
numbers.min # => 1 (natural comparison)
numbers.min_by { |n| n } # => 1 (same result)
# With custom logic, min_by shines
numbers.min_by { |n| -n } # => 9 (finds maximum via negative)
Performance Notes
min_byuses the spaceship operator (<=>) internally for comparisons- For enumerables that respond to
#<=>, this is efficient - When no block is given, Ruby 3.0+ returns an enumerator
# Ruby 3.0+ - lazy evaluation
enum = [5, 2, 8, 1, 9].min_by
enum.each { |n| puts n } # Still evaluates, but deferred
Return Value
Returns the element that minimizes the block’s return value, or nil if the collection is empty:
[].min_by { |x| x } # => nil
With n argument, returns an array of n elements:
[3, 1, 4, 1, 5, 9, 2, 6].min_by(2)
# => [1, 1]
Edge Cases
Empty collections return nil:
[].min_by(&:to_s) # => nil
Collections with one element return that element:
[42].min_by { |n| n } # => 42
See Also
Enumerable#inject— accumulate values with a blockEnumerable#each_with_object— iterate while building an accumulator objectEnumerable#group_by— group elements by a criteriaArray#map— transform each element into a new array