Как написать компаратор для сортировки?

212
26 апреля 2017, 11:54

Как отсортировать числовой массив?
Как отсортировать массив объектов по нескольким полям?

Answer 1
Стандартная сортировка

Функция sort по умолчанию приводит элементы массива к строкам, а затем сортирует.

[1,-8,90,32,0,0,5,92,900].sort()
// [-8, 0, 0, 1, 32, 5, 90, 900, 92]

Если массив состоит из чисел, то такое поведение является нежелательным.

Использование компаратора

Функция sort может принимать аргумент - компаратор.

Компаратор - это функция, которая принимает 2 аргумента и возвращает отрицательное число, если первый меньше, положительное, если второй меньше и 0, если они равны.

Для чисел достаточно распространено использование вычитания в качестве компаратора:

[1,-8,90,32,0,0,5,92,900].sort(function(a, b) {
  return a-b;
})
// [-8, 0, 0, 1, 5, 32, 90, 92, 900]

Вообще, следует с осторожностью относиться к этой конструкции из-за возможного переполнения, но в большинстве случаев она работает.

Компаратор на основе сравнения

Можно вспомнить, что во многих языках true приводится к 1, а false - к 0.

Воспользуемся этой возможностью. Только одно из условий a<b и b<a истинно, поэтому разность (b<a) - (a<b) хзаммечательно подходит на роль компаратора:

[1,-8,90,32,0,0,5,92,900].sort(function(a, b) {
  return (b<a) - (a<b);
})
// [-8, 0, 0, 1, 5, 32, 90, 92, 900]

Какие тут плюсы? Помимо невозможности переполнения, такое сравнение можно использовать не только с числами. Например, строки вычитать мы не можем, а сравнивать можем.

Для сортировки по убыванию надо просто поменять сравнения местами:

[1,-8,90,32,0,0,5,92,900].sort(function(a, b) {
  return (a<b) - (b<a);
})
// [900, 92, 90, 32, 5, 1, 0, 0, -8]
Сортировка по нескольким полям

При сравнении по нескольким полям требуется, чтобы следующее поле сравнивалось только когда предыдущие равны. Это значит, что часть компаратора, выполняющая сравнение тех полей при вычислении даёт 0.

Таким образом, для объединения сравнений полей замечательно подходит оператор ||, возвращающий первое истинное (в нашем случае ненулевое) значение, либо самое последнее (в нашем случае 0), если все ложны. Таким способом можно объединить любое количество полей.

Отсортируем массив по имени и id:

[{name:"John", id:7}, {name:"John",id:4}, {name:"Adam",id:3}, {name:"Adam",id:30}, {name:"Rose",id:1}].sort(function(a, b) {
  return (b.name<a.name) - (a.name<b.name) || (b.id<a.id) - (a.id<b.id);
})
// [{"name":"Adam","id":3},{"name":"Adam","id":30},{"name":"John","id":4},{"name":"John","id":7},{"name":"Rose","id":1}]
READ ALSO
JavaScript. Сетка изображений

JavaScript. Сетка изображений

ЗдравствуйтеНужно создать сетку с изображениями (изображения выбираются рандомно), которая будет выводиться в div "pictures" после нажатия на кнопку

262
Тормозит приложение при наборе текста

Тормозит приложение при наборе текста

Есть приложение, использующее React в связке с Redux

297
Как перекинуть данные в HTML таблицу? Не могу перекинуть данные с тегов в таблицу(

Как перекинуть данные в HTML таблицу? Не могу перекинуть данные с тегов в таблицу(

Немного модифицировал ваш код в сниппет, в котором видно, что после вызова open значение thisreadyState = 1, а после send значение this

214