Enumerable#max
The max method returns the largest element in an enumerable collection. It compares elements using the <=> operator (spaceship operator) to determine order.
Use max when the collection already has a meaningful order and you want the highest item from that order. Numbers, strings, and objects with a clear <=> method work well. If the rule depends on a field or calculation, the block form keeps that rule close to the call.
Basic Usage
Without arguments, max returns the single largest element:
[3, 1, 4, 1, 5, 9, 2, 6].max
# => 9
["banana", "apple", "cherry"].max
# => "cherry"
Beyond the single largest element, max accepts an integer argument to return a ranked list of the top N items. This is useful for leaderboards, top sellers, or any scenario where the ranking matters more than the absolute maximum.
getting the n largest elements
Pass an integer n to get the n largest elements as an array:
[3, 1, 4, 1, 5, 9, 2, 6].max(3)
# => [9, 6, 5]
["banana", "apple", "cherry", "date"].max(2)
# => ["date", "cherry"]
The n form is useful when you want a ranked shortlist instead of a single value. It still returns a plain array, so the result can be displayed, sliced, or passed into another method without extra conversion.
custom comparison with a block
You can provide a block to define custom comparison logic:
[-5, 3, -1, 7, -2].max { |a, b| a.abs <=> b.abs }
# => 7
["hello", "world", "ruby"].max { |a, b| a.length <=> b.length }
# => "hello"
The block must return -1, 0, or 1 (using the spaceship operator convention).
Keep the comparison block small enough that the ordering rule is obvious. If you are choosing by price, score, or length, max_by may read more directly because it asks for the value to compare instead of a full pairwise comparison.
handling empty collections
max returns nil when called on an empty collection:
[].max
# => nil
[].max(2)
# => []
That difference is important when the collection may be empty. The single-value form gives you nil, while the multi-value form gives you an empty array. Check for the shape you expect before chaining methods on the result.
max vs max_by
These two methods are often confused but behave differently:
| Method | What it compares |
|---|---|
max | Compares elements by their actual value using <=> |
max_by | Compares elements by the result of the block |
# max compares by value
[1, 2, 3].max
# => 3
# max_by compares by block result
["one", "two", "three"].max_by { |s| s.length }
# => "three"
Choosing between max and max_by depends on whether the comparison rule lives on the object itself or needs to be computed from a field. The examples below show both patterns with real data structures.
Practical Examples
The comparison block receives two elements and must return -1, 0, or 1 using the spaceship convention. When you are comparing by a single attribute like price or length, max_by often reads more directly because it asks for the value to compare rather than a full pairwise comparison.
finding the highest price
products = [
{ name: "Widget", price: 29.99 },
{ name: "Gadget", price: 49.99 },
{ name: "Doohickey", price: 19.99 }
]
expensive = products.max { |a, b| a[:price] <=> b[:price] }
expensive[:name]
# => "Gadget"
When the comparison rule is more specific than the default order, the block form lets you spell out exactly what “largest” means. For strings, you might compare by length rather than alphabetical position.
For strings, you might compare by length rather than alphabetical position, which changes what max considers the largest entry. The block form keeps this custom rule visible right at the call site.
finding the longest string
words = ["elephant", "cat", "giraffe", "ant"]
longest = words.max { |a, b| a.length <=> b.length }
# => "giraffe"
You can also ask for the top N items ranked by a custom comparison, which returns a sorted array of the largest entries. This works well when the collection contains structured data and the comparison targets a specific field.
getting the n most expensive items
products = [
{ name: "Widget", price: 29.99 },
{ name: "Gadget", price: 49.99 },
{ name: "Doohickey", price: 19.99 },
{ name: "Thingamajig", price: 39.99 }
]
products.max(2) { |a, b| a[:price] <=> b[:price] }
# => [{:name=>"Gadget", :price=>49.99}, {:name=>"Thingamajig", :price=>39.99}]
Custom objects can define their own comparison rules by implementing the spaceship operator. This lets max work on domain types without a block, because the class itself knows how to rank its instances.
When the class implements the spaceship operator, max automatically returns the highest-ranked instance using that comparison logic. In performance-sensitive code, max_by can be a better choice because it evaluates the block once per element rather than recomparing during a sort-like pass.
working with custom objects
class Player
attr_reader :score
def initialize(name, score)
@name = name
@score = score
end
def <=>(other)
@score <=> other.score
end
def to_s
@name
end
end
players = [
Player.new("Alice", 95),
Player.new("Bob", 87),
Player.new("Charlie", 92)
]
players.max
# => Alice (score: 95)
When the class implements <=>, max returns the object with the highest rank using the comparison logic already defined on the type. In performance-sensitive code, max_by can be a better choice because it evaluates the block once per element rather than re-comparing during a sort-like pass.
Performance Notes
max uses the <=> operator to compare elements. For arrays, it performs a single pass through the collection — O(n) time complexity.
When using max with a block, the comparison logic runs multiple times during the sort. For finding a single maximum, max_by is often more efficient since it only evaluates the block once per element.
In day-to-day code, max is clearest when the objects already know how to compare themselves. Use the block form for special rules and prefer max_by when you are selecting by one derived value.
See Also
- /reference/enumerable/enumerable-min/ — returns the smallest element
- /reference/enumerable/enumerable-first/ — get the first element
- /reference/enumerable/enumerable-select/ — filter elements by condition