Enumerable#max_by
Object · Added in v1.8.6 · Updated March 16, 2026 · Enumerable The max_by method returns the element that would be largest according to the criteria you define in a block. Unlike max which compares elements directly, max_by lets you specify how to compare them.
How It Works
max_by evaluates the block for each element and returns the element that produced the largest value:
collection.max_by { |element| block_return_value }
The element itself is returned, not the block’s return value.
Basic Usage
Find the longest string in an array:
words = ["cat", "elephant", "dog", "hippopotamus"]
longest = words.max_by { |word| word.length }
# => "hippopotamus"
Find the oldest person in a collection:
people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 }
]
oldest = people.max_by { |person| person[:age] }
# => {:name=>"Charlie", :age=>35}
With Nested Comparisons
When multiple elements produce the same maximum value, max_by returns the first one encountered:
words = ["aa", "bb", "cc", "dd"]
result = words.max_by { |w| w[0] }
# => "aa" (all have the same value, first one wins)
Finding Multiple Maximum Elements
Use max_by with an argument to get multiple maximum elements:
numbers = [5, 2, 8, 1, 9, 3, 7, 4, 6]
largest_three = numbers.max_by(3) { |n| n }
# => [9, 8, 7]
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 }
]
expensive_three = products.max_by(3) { |p| p[:price] }
# => [{:name=>"Laptop", :price=>999}, {:name=>"Phone", :price=>699}, {:name=>"Tablet", :price=>449}]
With Arrays of Arrays
pairs = [[1, 5], [3, 2], [2, 8], [4, 1]]
# Find pair with largest first element
by_first = pairs.max_by { |pair| pair[0] }
# => [3, 2]
# Find pair with largest second element
by_second = pairs.max_by { |pair| pair[1] }
# => [2, 8]
Practical Examples
Finding the Longest Method Name
methods = [:to_s, :inspect, :class, :object_id, :nil?]
longest = methods.max_by { |m| m.to_s.length }
# => :object_id (9 characters)
Finding the Fastest Shipping Option
shipping_options = [
{ carrier: "USPS", weight: 5, distance: 100 },
{ carrier: "FedEx", weight: 5, distance: 50 },
{ carrier: "UPS", weight: 5, distance: 75 }
]
fastest = shipping_options.max_by { |opt| 1.0 / (opt[:weight] * opt[:distance]) }
# => {:carrier=>"FedEx", :weight=>5, :distance=>50}
Finding the Furthest 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 }
]
furthest = locations.max_by { |loc|
(loc[:x] - current_location[:x]).abs + (loc[:y] - current_location[:y]).abs
}
# => {:name=>"Home", :x=>15, :y=>15}
Comparison with max
| Method | Use When |
|---|---|
max | You want natural/built-in comparison |
max_by | You need custom comparison logic |
numbers = [5, 2, 8, 1, 9]
numbers.max # => 9 (natural comparison)
numbers.max_by { |n| n } # => 9 (same result)
# With custom logic, max_by shines
numbers.max_by { |n| -n } # => 1 (finds minimum via negative)
Performance Notes
max_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].max_by
enum.each { |n| puts n } # Still evaluates, but deferred
Return Value
Returns the element that maximizes the block’s return value, or nil if the collection is empty:
[].max_by { |x| x } # => nil
With n argument, returns an array of n elements:
[3, 1, 4, 1, 5, 9, 2, 6].max_by(2)
# => [9, 6]
Edge Cases
Empty collections return nil:
[].max_by(&:to_s) # => nil
Collections with one element return that element:
[42].max_by { |n| n } # => 42
See Also
Enumerable#min_by— find the minimum element by a criteriaEnumerable#inject— accumulate values with a blockEnumerable#each_with_object— iterate while building an accumulator objectArray#map— transform each element into a new array