Почему функция сравнения функции sort() работает именно так?

#javascript #arrays #sorting

Вопрос:

Я читал в документации о работе функции сравнения. Эта функция обратного вызова может иметь 2 параметра. Для них есть 3 «если» :

  • Если compareFunction(a, b) возвращает значение > 0, отсортируйте b перед a.
  • Если compareFunction(a, b) возвращает значение
  • Если compareFunction(a, b) возвращает 0, a и b считаются равными.

Итак, насколько я вижу, если функция сравнения возвращает значение меньше нуля, алгоритм сравнения ничего не делает ( a и b остается на тех же местах). И если эта функция возвращает значение больше нуля, a и b переключается ( b идет первым).

Ладно, это понятно. Но почему мой приведенный ниже код работает именно так?

 let arr1 = [9, 3, 6, 7, 1];
console.log(arr1.sort((a, b) => 1)); //1 > 0 -> compare function should switch elements

let arr2 = [9, 3, 6, 7, 1];
console.log(arr2.sort((a, b) => -1)); //-1 < 0 -> compare function shouldn't switch elements 

Комментарии:

1. Ты сортируешь arr1 дважды -> console.log(arr2.sort((a, b) => -1))

2. Проблема в том, что ваши функции сравнения несовместимы. Например, в первом фрагменте как сравнения (9,3) , так и (3,9) возврат 1. И если это так, то результат функции сортировки не определен. То же самое касается второго фрагмента.

3. Андреас, поскольку первый результат вернул массив, который не был отсортирован по-другому, это не повлияло на результат 😉

4. @derpirscher предоставленная функция поиска не является несуществующей. он возвращает одно и то же для каждой пары

5. функция сравнения не должна переключать элементы , как вы говорите, и это не так

Ответ №1:

Ваша интерпретация документов неверна.

Ты говоришь

-1 означает, что элементы должны оставаться на одном и том же месте.

Это неправильно, в документах просто указано, что -1 означает, что a должно быть отсортировано перед b.

В зависимости от базового алгоритма сортировки нет никакой гарантии, что при вызове функции comparefunction с параметрами a и b которые a в данный момент находятся b в массиве. Т. е. представьте себе массив [1,2,3] . Возможно, функция сравнения вызывается с параметрами (3, 1) или (1,3) . Но если вы вернетесь -1 в первом случае, 1 то и 3 впрямь поменяетесь местами. И наоборот, если вы вернетесь 1 во втором случае 1 и 3 снова поменяетесь местами.

Редактировать

Разные браузеры реализуются sort по-разному. Например, если вы выполните следующий фрагмент кода в chrome и firefox, вы получите разные результаты.

 var arr = [1,2,3,4,5,6,7,8,9];
arr.sort((a,b) => {
    console.log(`${a}  ${b}`);
  return 1;
})
console.log(arr); 

Например, в моем текущем chrome (версия 94.0.4606.61 в Windows) b будет меньше, чем a для всех вызовов функции сравнения, и, таким образом, возврат 1 из функции сравнения будет означать сортировку b до a того, как это уже произойдет. Таким образом, ничего не изменится.

Где в моем firefox (версия 92.0 в Windows) b будет больше, чем a для всех вызовов функции сравнения. И, таким образом , возврат 1 из функции сравнения снова означал бы сортировку b раньше a , что в настоящее время не так. Таким образом, массив будет перевернут …

Другие периоды выполнения с другой реализацией sort могут снова привести к другим совершенно непредсказуемым результатам …

Ответ №2:

Если функция сравнения возвращает неправильный ответ на фундаментальный вопрос, значение которого меньше другого, почему бы вам не ожидать неправильного ответа от функции, которая зависит от него?

Алгоритм сортировки, вероятно, делает эквивалент двух проходов, прежде чем он будет выполнен, и в конечном итоге возвращает значения на свое место при втором проходе.

Я говорю эквивалентно — это может быть один раз, но для элементов с более низким индексом он сортирует его в одну сторону, а для более высоких элементов-в другую.

Во втором случае он считает, что верхние элементы отсортированы, а затем нижние элементы, которые он считает необходимым переключить.

Но все виды работают по-разному. Сортировка слиянием может зависеть от того, сколько раз она делится на 2. Быстрая сортировка может зависеть от положения поворота. Сортировка вставки может зависеть от количества четных или нечетных элементов.

Итак, философия в стороне, фундаментальный вопрос заключается в следующем:

 compare(1, 2) = 1, so switch.
compare(2, 1) = 1, so switch.
 

Если вам нужна была причина, по которой ваша плохая функция сравнения заставила сортировку вести себя именно так, вот почему.

Если вы действительно хотели, чтобы он изменил сортировку, то вам нужно что-то вроде:

 function compare(int a, int b)
{
  if (a < b) return 1;
  if (a > b) return -1;
  return 0;
}