Array#max
Array#max, Array#min, and Array#minmax return the largest and smallest elements in an array. These methods were added directly to the Array class in Ruby 2.4, making them significantly faster than their Enumerable counterparts since they avoid the overhead of iterating through #each.
They are especially handy when you already know you are working with an array and do not need the extra flexibility of Enumerable. That makes them a good fit for scoring lists, ranking records, and pulling a range of values out of a small in-memory collection.
Key takeaways
max,min, andminmaxare direct array methods, so they avoid the extraEnumerableoverhead.- Use
minmaxwhen you need both ends of a range in one pass. - Use the block form when the natural sort order is not the one you want.
max(n)andmin(n)are useful when you need a handful of extremes instead of a single value.- For arrays, these methods are usually the clearest and fastest option.
Syntax
arr.max # returns maximum element
arr.max(n) # returns array of n largest elements
arr.max { |a,b| } # returns maximum using block comparison
arr.min # returns minimum element
arr.min(n) # returns array of n smallest elements
arr.min { |a,b| } # returns minimum using block comparison
arr.minmax # returns [min, max] as two-element array
arr.minmax { |a,b| } # returns [min, max] using block comparison
Each variant serves a different need: max for the single largest value, max(n) for the top n items, min and min(n) for the complementary bottom end, and minmax when you need both extremes at once. The block form lets you override the natural sort order, which is essential when comparing by a derived property rather than the raw element value.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
n | Integer | nil | When provided, returns an array of the n largest/smallest elements |
All methods also accept an optional block that defines custom comparison logic, overriding the default <=> operator.
Examples
Basic usage with numbers
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# Find the maximum
numbers.max
# => 9
# Find the minimum
numbers.min
# => 1
# Get both at once
numbers.minmax
# => [1, 9]
The minmax method returns a two-element array with the minimum first and the maximum second, giving you both ends of the range in a single pass through the data. This is more efficient than calling min and max separately, and the result can be destructured directly into two variables.
Get multiple extremes
scores = [95, 87, 92, 88, 79, 91, 85, 90]
# Get top 3 scores
scores.max(3)
# => [95, 92, 91]
# Get bottom 3 scores
scores.min(3)
# => [79, 85, 87]
When you pass an integer argument to max or min, the method returns an array of the n largest or smallest elements rather than a single value. The returned elements are sorted in descending order for max(n) and ascending order for min(n), which makes the result ready to use without further sorting.
With strings (alphabetical comparison)
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
fruits.max
# => "elderberry"
fruits.min
# => "apple"
fruits.minmax
# => ["apple", "elderberry"]
Strings compare alphabetically by default, so max returns the last word in dictionary order and min returns the first. This behaviour comes from Ruby’s built-in <=> operator on strings, which follows lexicographic ordering rules rather than any notion of string length or content meaning.
Using a block for custom comparison
words = ["cat", "elephant", "bat", "ant"]
# Compare by length
words.max { |a, b| a.length <=> b.length }
# => "elephant"
words.min { |a, b| a.length <=> b.length }
# => "bat"
# Get extremes by length
words.minmax { |a, b| a.length <=> b.length }
# => ["bat", "elephant"]
The block form is where these methods show their real flexibility. By changing the comparison from the default <=> to a length-based comparison, the same method calls find extremes by a completely different criterion. Any computable property can become the basis for ordering, from string length to object attributes to calculated scores.
With empty arrays
empty = []
empty.max
# => nil
empty.min
# => nil
empty.minmax
# => [nil, nil]
empty.max(3)
# => []
empty.min(3)
# => []
Empty arrays return nil for the single-element forms and an empty array for the n-element forms. This consistent handling means callers do not need to guard against empty collections before calling these methods, though they should still check for nil when using the single-element return value in further computations.
Finding extremes in hashes by value
prices = { apple: 1.50, banana: 0.75, orange: 2.00, mango: 3.50 }
# Convert to array of [key, value] pairs
items = prices.to_a
# Most expensive
items.max { |a, b| a[1] <=> b[1] }
# => [:mango, 3.50]
# Cheapest
items.min { |a, b| a[1] <=> b[1] }
# => [:banana, 0.75]
Converting a hash to an array of pairs and then using max or min with a block that compares the value column is a practical pattern when you need to find the highest or lowest price, score, or any other numeric attribute stored as a hash value. The block receives two [key, value] pairs and compares their second elements.
Common patterns
Check for highest/lowest values
# Simple case: get extremes
data = [23, 45, 12, 67, 34]
highest = data.max
lowest = data.min
# More explicit with interpolation
puts "Range: #{lowest} to #{highest}"
# => Range: 12 to 67
A simple max or min call is often all you need to answer a question about a dataset. The result slots directly into string interpolation or conditional logic, and the method name makes the intent obvious to anyone reading the code later.
Avoid multiple iterations
# Bad: iterates twice
max_value = data.max
min_value = data.min
# Good: iterates once
min_val, max_val = data.minmax
This matters with large datasets where the difference between one pass and two passes is noticeable. For collections with thousands of elements, the savings from a single traversal can be significant, especially in request-handling code where every millisecond counts. The minmax method was added specifically to address this common case of needing both extremes at once.
Using with sort
data = [5, 2, 8, 1, 9]
# These are equivalent but max/min is faster
data.max # => 9
data.sort.last # => 9
data.min # => 1
data.sort.first # => 1
Performance note
Array’s native #max and #min (Ruby 2.4+) are 10x faster than Enumerable’s versions because they skip the call to #each. If you’re working with Arrays specifically, always prefer these over the Enumerable methods.
The speed difference is most visible when the array is large or when the comparison logic is repeated often. In smaller code paths the readability gain matters more than the raw performance gain, but it is still nice to know that the direct array methods are the cheaper option.
Error cases
# With n > array length, returns all elements (sorted)
[1, 2].max(10)
# => [2, 1]
# With n = 0, returns empty array
[1, 2].max(0)
# => []
# nil in array works fine
[1, nil, 3].max
# => 3
# Comparison must be defined
[Object.new, Object.new].max
# => ArgumentError: comparison of Object with Object failed
When you are choosing between max, min, and minmax, think about how many times you need to scan the data. If you need both ends, minmax is usually the clearest option because it returns both values in one pass. If you only care about one extreme, the single-purpose method keeps the intent obvious.
Conclusion
Array#max, Array#min, and Array#minmax give you a direct way to find extremes without bouncing through Enumerable. That keeps the code small, the intent obvious, and the performance predictable. When the data is already an array, these methods are usually the simplest place to start.