Я только что закончил вторую неделю погружения в программную инженерию в школе Flatiron, и я собираюсь распознать разницу между .sort и .sort_by в Ruby. Я впервые столкнулся с .sort_by, когда работал над последней лабораторной работой в предварительной работе над моей программой. Лаборатория называлась «По алфавиту на эсперанто», имея в виду международный вспомогательный язык, известный как эсперанто. Соревнование? Написать метод, который принимает массив строк и сортирует их в алфавитном порядке в соответствии с алфавитом эсперанто. Я решил лабораторную работу, используя .sort_by, но даже в этом случае я все еще не был уверен, как .sort_by работает «под капотом» и чем он отличается от .sort. Итак, я решил погрузиться в дело. Вот что я узнал.

Как работает .sort:

.sort - это перечислитель Ruby, который одновременно сравнивает два элемента в массиве. Его можно вызывать с блоком или без него, но если он вызывается с блоком, блок требует два аргумента, которые представляют две сравниваемые вещи. При вызове без блока .sort неявно полагается на оператор метода сравнения ‹=› (обычно называемый оператором космического корабля). Оператор космического корабля вводит в действие каскадный оператор if / elsif / else, который возвращает 0, если два операнда равны друг другу, -1, если первый операнд меньше второго, и 1, если первый операнд больше второго. Эти возвращаемые значения перемещают элементы вверх и вниз по списку, пока они не будут в указанном порядке.

Как работает .sort_by:

В отличие от .sort, .sort_by должен использоваться с блоком, и блок принимает только один аргумент. При использовании .sort_by вы обычно хотите каким-то образом манипулировать аргументом, чтобы сделать его доступным для сортировки. Например, если вы хотите отсортировать массив строк по длине, вы должны вызвать:

string_array.sort_by { |string| string.length }

.sort_by работает, создавая то, что вы можете представить как невидимый хеш. При вызове массива он вычисляет набор цифровых ключей (известных как «ключи сортировки») и присваивает каждому элементу в массиве один из этих ключей сортировки. Затем ключи сортируются и снова отображаются на исходные значения. Возвращаемое значение - отсортированный массив.

Учитывая это различие, давайте разберемся с решением задачи «Упорядочить эсперанто по алфавиту».

Для начала предположим, что массив, который мы хотим расположить по алфавиту эсперанто, выглядит следующим образом:

sentences_array = ["mi amas programadon", "ruby estas mia plej ŝatata lingvo", "ni ordigu ĉi tiujn frazojn",  "laboru fervore ludu fervore", "ĉu vi ŝatas kodon"]

Нам также понадобится следующая константа:

ESPERANTO_ALPHABET = "abcĉdefgĝhĥijĵklmnoprsŝtuŭvz"

И это метод, который я написал, и я буду распаковывать его шаг за шагом:

Вот как это работает:

Шаг 1.

sentences_array.sort_by do |sentence|

С помощью этой строки я вызываю метод .sort_by для набора предложений. Каждое предложение в массиве будет передано в блок как «предложение». Итак, в первый раз «предложение» будет «mi amas programadon» (разве это правда?).

Шаг 2.

sentence.split("").map do |character|
  ESPERANTO_ALPHABET.index(character)
end

Здесь я превращаю предложение в массив, где каждый элемент массива представляет собой букву в предложении. Затем я вызываю .map для этого массива, что означает, что я буду отображать новое значение в соответствии с кодом в блоке на каждый элемент массива букв. Итак, массив букв будет иметь такое же количество элементов, как и изначально, но каждый элемент будет преобразован.

Например, если «предложением» является «mi amas programadon», оно преобразуется в массив [«m», «i», ««, «a», «m», «a», «s», «« , «P», «r», «o», «g», «r», «a», «m», «a», «d», «o», «n»]. Каждый элемент в этом массиве будет передан в блок как «символ».

Первый элемент, который мы называем «персонажем», - это «m». Блок вызовет:

ESPERANTO_ALPHABET.index("m")

.index (), при вызове строки, работает, показывая, какая буква в строке (численно) соответствует тому, что передается в .index () в качестве аргумента (помните, что строки, как и массивы, индексируются 0) . В этом случае «m» соответствует индексу 16 в ESPERANTO_ALPHABET, поэтому 16 заменяет «m» в массиве букв. К концу цикла наш исходный массив будет выглядеть так:

["16", "11", "nil", "0", "16", "0", "21", "nil", "19", "20", "18", "7", "20", "0", "16", "0", "4", "18", "17"]

Шаги 1 и 2 будут выполняться для каждого предложения в исходном массиве предложений.

Шаг 3:

Пришло время магии .sort_by. У нас есть пять предложений (в настоящее время представленных в виде массивов с целыми числами в качестве элементов), поэтому представьте, что .sort_by генерирует пять числовых ключей: 1, 2, 3, 4 и 5. Он присваивает первое предложение (помните, что в настоящее время оно представлено массивом содержащий кучу целых чисел) к первому ключу. Затем следует второе предложение (также представленное массивом, содержащим кучу целых чисел). Если первое целое число во втором предложении меньше первого целого числа в первом предложении, второе предложение присваивается ключу 1, а первое предложение перемещается вниз к ключу 2. И так далее. В конце концов, вы можете представить себе хеш, который выглядит так:

sorted_hash = {
  "1" => ["3", "24", "nil", "26", "11", "22", "0", "23", "0", "21", "nil", "14", "18", "4", "18", "17"],
  "2" => ["15", "0", "1", "18", "20", "24", "nil", "6", "5", "20", "26", "18", "20", "5", "nil", "15", "24", "4", "24", "nil", "6", "5", "20", "26", "18", "20", "5"],
  "3" => ["16", "11", "nil", "0", "16", "0", "21", "nil", "19", "20", "18", "7", "20", "0", "16", "0", "4", "18", "17"],
  "4" => ["17", "11", "nil", "18", "20", "4", "11", "7", "24", "nil", "3", "11", "nil", "23", "11", "24", "12", "17", "nil", "6", "20", "0", "27", "18", "12", "17"],
  "5" => ["20", "24", "1", "nil", "nil", "5", "21", "23", "0", "21", "nil", "16", "11", "0", "19", "15", "5", "12", "nil", "22", "0", "23", "0", "23", "0", "nil", "15", "11", "17", "7", "26", "18"]
}

Затем метод .sort_by сопоставляет эти ключи сортировки с исходными значениями:

sorted_hash = {
  "1" => "ĉu vi ŝatas kodon",
  "2" => "laboru fervore ludu fervore",
  "3" => "mi amas programadon",
  "4" => "ni ordigu ĉi tiujn frazojn",
  "5" => "ruby estas mia plej ŝatata lingvo"
}

Наконец, метод .sort_by вернет массив с элементами в следующем порядке:

["ĉu vi ŝatas kodon", "laboru fervore ludu fervore", "mi amas programadon", "ni ordigu ĉi tiujn frazojn", "ruby estas mia plej ŝatata lingvo"]

Вот и все! Нет космических кораблей с .sort_by; вместо этого все дело в ключах сортировки.