Reason #127 •
May 7th, 2026
Enumerable#max_by and Enumerable#min_by
To wrap up yesterday's minimum / maximum theme, let's look at Enumerable#max_by and Enumerable#min_by, which, similar to Enumerable#sort_by, allow us to find the maximum or minimum element in a collection based on a specific criterion defined by a block:
Ruby
Person = Struct.new(:name, :age)
people = [
Person.new("Alice", 30),
Person.new("Bob", 25),
Person.new("Charlie", 35)
]
# Find the oldest person
oldest = people.max_by(&:age)
oldest.name # => "Charlie"
# Find the youngest person
youngest = people.min_by(&:age)
youngest.name # => "Bob"
first_in_the_phonebook = people.min_by(&:name)
first_in_the_phonebook.name # => "Alice"
last_in_the_phonebook = people.max_by(&:name)
last_in_the_phonebook.name # => "Charlie"
# Just like with min and max we can also get more than one result
oldest_two = people.max_by(2, &:age)
oldest_two.map(&:name) # => ["Charlie", "Alice"]
JavaScript
const people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 }
];
const oldest = people.reduce(
(oldest, person) => person.age > oldest.age ? person : oldest
);
oldest.name; // "Charlie"
const youngest = people.reduce(
(youngest, person) => person.age < youngest.age ? person : youngest
);
youngest.name; // "Bob"
const firstInThePhonebook = people.reduce(
(first, person) => person.name < first.name ? person : first
);
firstInThePhonebook.name; // "Alice"
const lastInThePhonebook = people.reduce(
(last, person) => person.name > last.name ? person : last
);
lastInThePhonebook.name; // "Charlie"
// To get more than one result, we can sort the array and take
// the top N elements:
const oldestTwo = [...people].sort(
(a, b) => b.age - a.age
).slice(0, 2);
oldestTwo.map(person => person.name); // ["Charlie", "Alice"]
We also have minmax_by, which returns both the minimum and maximum elements in a single pass:
Ruby
youngest, oldest = people.minmax_by(&:age)
youngest.name # => "Bob"
oldest.name # => "Charlie"
JavaScript
const { min: youngest, max: oldest } = people.reduce(
(result, person) => {
if (person.age < result.min.age) result.min = person;
if (person.age > result.max.age) result.max = person;
return result;
},
{ min: people[0], max: people[0] }
);
youngest.name; // "Bob"
oldest.name; // "Charlie"
So very handy!
History
Enumerable#min_by and max_by as well as minmax_by shipped in Ruby 1.8.7, released in May 2008.
Ruby 2.2, released in 2012, later extended min_by and max_by with an optional count argument, matching the extension made to min and max.