У меня есть массив объектов, таких как:

var arr = [{index: 1, key: undefined}, {index: 2, key: undefined},{index: 3, key: undefined},{index: 4, key: undefined},{index: 5, key: undefined},{index: 6, key: undefined},{index: 7, key: undefined},{index: 8, key: undefined},{index: 9, key: undefined},{index: 10, key: undefined},{index: 11, key: undefined},{index: 12, key: undefined},{index: 13, key: undefined},{index: 14, key: undefined},{index: 15, key: undefined},{index: 16, key: undefined},{index: 17, key: undefined},{index: 18, key: undefined},{index: 19, key: undefined} ]

Я хочу отсортировать массив arr по ключу - здесь все неопределенное значение. Возвращаемое значение должно совпадать с arr. Но когда я выполню:

arr.sort(function(a,b){return a.key - b.key})

Результат не такой, как я ожидал, порядок массива изменился. Есть идеи по этой проблеме?

Мой результат: https://imgur.com/a/4NyDq

Обновление: протестировано с другим массивом:

var b = [{index: 1, key: 10}, {index: 2, key: 10},{index: 3, key: 10},{index: 4, key: 10},{index: 5, key: 10},{index: 6, key: 10},{index: 7, key: 10},{index: 8, key: 10},{index: 9, key: 10},{index: 10, key: 10},{index: 11, key: 10},{index: 12, key: 10},{index: 13, key: 10},{index: 14, key: 10},{index: 15, key: 10},{index: 16, key: 10},{index: 17, key: 10},{index: 18, key: 10},{index: 19, key: 10} ]

Каждый ключ имеет одинаковое значение, но когда вызывается функция сортировки: https://imgur.com/a/I7kiI

IE и Firefox работают нормально, проблема возникает в Chrome. Я предполагаю, что что-то пошло не так с возвращением 0.

0
vicnoob 2 Мар 2018 в 06:16

3 ответа

Лучший ответ

Проблема связана со стабильностью алгоритмов, используемых внутри реализации array.sort, которая зависит от механизма, используемого для выполнения вашего кода JavaScript.

Chrome использует механизм Google V8. Алгоритм сортировки V8 использует комбинацию insert-sort и quick-sort . Проверьте фактическую реализацию здесь.

Вставка-сортировка используется, когда массив небольшой (array.length <= 10), в противном случае используется быстрая сортировка . Второй алгоритм сортировки нестабилен и не дает никаких гарантий о сохранении порядка эквивалентных элементов.

В заключение я включаю два теста (оба с использованием вашей начальной функции сравнения). Результаты Chrome:

  • первая сортировка выполняется по массиву из 10 элементов (следовательно, исходный порядок сохраняется)
  • вторая сортировка выполняется в исходном массиве с 19 элементами (в этом случае нет уверенности в сохранении исходного порядка, и поэтому порядок в массиве изменяется)
const small = [
  {index: 1, key: undefined}, 
  {index: 2, key: undefined},
  {index: 3, key: undefined},
  {index: 4, key: undefined},
  {index: 5, key: undefined},
  {index: 6, key: undefined},
  {index: 7, key: undefined},
  {index: 8, key: undefined},
  {index: 9, key: undefined},
  {index: 10, key: undefined}
];

// stable sort
small.sort(function(a,b){return a.key - b.key});
console.log(small);

var arr = [
  ...small,
  {index: 11, key: undefined},
  {index: 12, key: undefined},
  {index: 13, key: undefined},
  {index: 14, key: undefined},
  {index: 15, key: undefined},
  {index: 16, key: undefined},
  {index: 17, key: undefined},
  {index: 18, key: undefined},
  {index: 19, key: undefined}
];

// unstable sort
arr.sort(function(a,b){return a.key - b.key});
console.log(arr);

Вероятно, вам нужно реализовать алгоритм стабильной сортировки, чтобы гарантировать, что ваш код будет вести себя одинаково, несмотря на среду, в которой он будет выполняться. Наиболее распространенными стабильными алгоритмами являются пузырьковая сортировка, insert-sort и Merge сортировки.

Подробнее о стабильности в алгоритмах сортировки ...

Проверьте ошибку хрома: V8 не стабильная сортировка

механизмы Javascript. Подробнее.

2
Carloluis 2 Мар 2018 в 05:36

Сделайте следующее ....

arr.sort(function(a,b){return (!a || !b)? 0 : (a.key - b.key) })
0
Rohit Tirmanwar 2 Мар 2018 в 03:41

То, что вы пытаетесь сделать, это вычесть undefined из undefined, и в результате вы получите NaN.

NaN < 0
> false

NaN > 0
> false

NaN не является -1 и не является 1, и он не больше и не меньше 0, поэтому, похоже, он рассматривается как 0.

Я не уверен, что приведенное выше предложение верно.

Согласно MDN :

Если compareFunction (a, b) возвращает 0, оставьте a и b неизменными по отношению друг к другу, но отсортированные по всем различным элементам. Примечание. Стандарт ECMAscript не гарантирует такого поведения, и поэтому не все браузеры (например, версии Mozilla, выпущенные как минимум в 2003 году) соблюдают это.

Итак, я проверил это в Firefox и порядок остался неизменным. Но то же самое в Chrome воспроизвело вашу проблему.

1
Roomy 2 Мар 2018 в 04:04