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.

Reason #128 ?