Как можно сортировать массивы и хэши?ruby-29

Сортировка - одна из фундаментальных операций при работе с коллекциями. Ruby предоставляет богатый набор методов для сортировки массивов и хэшей, каждый из которых имеет свои особенности.

Сортировка массивов

1. Базовые методы сортировки

numbers = [3, 1, 4, 2]

# sort - возвращает новый отсортированный массив
numbers.sort #=> [1, 2, 3, 4]

# sort! - сортирует исходный массив
numbers.sort! # теперь numbers == [1, 2, 3, 4]

# sort_by - сортировка по результату блока
['apple', 'pear', 'banana'].sort_by { |word| word.length }
#=> ["pear", "apple", "banana"]

2. Сортировка в обратном порядке

# reverse после sort
[3, 1, 4, 2].sort.reverse #=> [4, 3, 2, 1]

# sort с отрицательным сравнением
[3, 1, 4, 2].sort { |a, b| b <=> a } #=> [4, 3, 2, 1]

3. Кастомная сортировка

# Сортировка по нескольким критериям
users = [
  {name: 'Alice', age: 25},
  {name: 'Bob', age: 30},
  {name: 'Alice', age: 20}
]

users.sort_by { |u| [u[:name], u[:age]] }
#=> [{:name=>"Alice", :age=>20}, {:name=>"Alice", :age=>25}, {:name=>"Bob", :age=>30}]

4. Сортировка с использованием <=>

# Кастомная логика сравнения
[5, 1, 3, 2, 4].sort { |a, b| a.odd? ? (b.odd? ? a <=> b : -1) : (b.odd? ? 1 : a <=> b) }
#=> [1, 3, 5, 2, 4] (сначала нечетные, затем четные)

Сортировка хэшей

Хэши в Ruby до версии 1.9 не сохраняли порядок элементов, но в современных версиях порядок сохраняется.

1. Сортировка по ключам

hash = {b: 2, a: 1, c: 3}

# Преобразование в массив и сортировка
hash.sort_by { |k, v| k } #=> [[:a, 1], [:b, 2], [:c, 3]]

# С сохранением в новый хэш (Ruby 3+)
hash.sort_by { |k, v| k }.to_h #=> {:a=>1, :b=>2, :c=>3}

2. Сортировка по значениям

hash = {a: 2, b: 1, c: 3}

# Сортировка по значению
hash.sort_by { |k, v| v } #=> [[:b, 1], [:a, 2], [:c, 3]]

3. Сложные критерии сортировки

people = {
  'Alice' => {age: 25, score: 85},
  'Bob' => {age: 30, score: 90},
  'Charlie' => {age: 25, score: 95}
}

# Сортировка по возрасту, затем по score
people.sort_by { |name, data| [data[:age], -data[:score]] }
#=> [["Alice", {:age=>25, :score=>85}], ["Charlie", {:age=>25, :score=>95}], ["Bob", {:age=>30, :score=>90}]]

Производительность

  1. sort_by обычно быстрее sort с блоком, так как вычисляет ключ сортировки один раз для каждого элемента
  2. Для больших массивов стоит рассмотреть:
    • Использование sort_by
    • Замену на более эффективные структуры данных
    • Использование parallel для многопоточной сортировки

Специальные случаи

# Сортировка строк с учетом локали
['é', 'a', 'ü', 'b'].sort_by { |s| s.downcase.unicode_normalize(:nfkd).gsub(/\p{Mn}/, '') }
#=> ["a", "b", "é", "ü"]

# Ленивая сортировка (Ruby 3.0+)
large_array.lazy.sort_by { |x| x.some_expensive_calculation }.first(10)

Резюмируем: Ruby предоставляет разнообразные методы сортировки как для массивов, так и для хэшей. Выбор конкретного метода зависит от требований к производительности, необходимости сохранения исходной коллекции и сложности критериев сортировки. Для большинства случаев sort_by является оптимальным выбором благодаря балансу читаемости и производительности.