Какова стабильность метода Array.sort () в разных браузерах? - PullRequest
60 голосов
/ 12 июня 2010

Я знаю, что спецификация скрипта ECMA не определяет, какой алгоритм использовать для сортировки массивов, и не указывает, должна ли сортировка быть стабильной.

Я нашел эту информацию для Firefox , который указывает, что firefox использует стабильную сортировку.

Кто-нибудь знает о IE 6/7/8, Chrome и Safari?

Ответы [ 4 ]

58 голосов
/ 12 июня 2010

Начиная с ES2019, sort должно быть стабильным.В ECMAScript 1-е издание до ES2018 разрешено быть нестабильным.

Простой тестовый случай (игнорируйте заголовок, второй набор чисел должен быть последовательным, если сортировка двигателя стабильна).Примечание: этот тестовый пример не работает для некоторых версий Chrome (технически, V8), которые переключали алгоритмы сортировки на основе размера массива, используя стабильную сортировку для небольших массивов, но нестабильную для больших массивов.( Подробности .) См. В конце вопроса об измененной версии, которая делает массив достаточно большим, чтобы вызвать поведение.

Сортировка IE была стабильной, пока я когда-либо использовалэто (так IE6).Повторная проверка в IE8, и, похоже, все еще так.

И хотя на той странице Mozilla, на которую вы ссылаетесь, указано, что сортировка Firefox стабильна, я определенно утверждаю, что до Firefox 2.0 (включая его) это не всегда было так.*

  • IE6 +: стабильный
  • Firefox <3: нестабильный </li>
  • Firefox> = 3: стабильный
  • Chrome <70: нестабильный </li>
  • Chrome> = 70: стабильный
  • Opera <10: нестабильный </li>
  • Opera> = 10: стабильный
  • Safari 4: стабильный
  • Край: нестабильный для длинных массивов (> 512 элементов )

Все тесты в Windows.

См. Также: Реализация алгоритма быстрой стабильной сортировки в javascript

Этот тестовый пример (изменен с здесь) продемонстрирует проблему в V8 (например, Node v6, Chrome

function Pair(_x, _y) {
    this.x = _x;
    this.y = _y;
}
function pairSort(a, b) {
    return a.x - b.x;
}
var y = 0;
var check = [];
while (check.length < 100) {
    check.push(new Pair(Math.floor(Math.random() * 3) + 1, ++y));
}
check.sort(pairSort);
var min = {};
var issues = 0;
for (var i = 0; i < check.length; ++i) {
    var entry = check[i];
    var found = min[entry.x];
    if (found) {
        if (found.y > entry.y) {
            console.log("Unstable at " + found.i + ": " + found.y + " > " + entry.y);
            ++issues;
        }
    } else {
        min[entry.x] = {x: entry.x, y: entry.y, i: i};
    }
}
if (!issues) {
    console.log("Sort appears to be stable");
}
14 голосов
/ 12 июня 2010

Я хотел бы поделиться трюком, который я обычно использую в C / C ++ для qsort().

JS 'sort () позволяет указать функцию сравнения.Создайте второй массив такой же длины и заполните его возрастающими числами от 0.

function stableSorted(array, compareFunction) {
  compareFunction = compareFunction || defaultCompare;
  var indicies = new Array(array.length);
  for (var i = 0; i < indicies.length; i++)
    indicies[i] = i;

Это индексы в исходном массиве.Мы собираемся отсортировать второй массив.Создайте пользовательскую функцию сравнения.

  indicies.sort(function(a, b)) {

Она получит два элемента из второго массива: используйте их как индексы в исходных массивах и сравните элементы.

    var aValue = array[a], bValue = array[b];
    var order = compareFunction(a, b);
    if (order != 0)
      return order;

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

   if (a < b)
     return -1;
   else
     return 1;
  });

После сортировки () второй массив будет содержать индексы, которые можно использовать для доступа к элементам исходного массива в стабильной сортировке.order.

  var sorted = new Array(array.length);
  for (var i = 0; i < sorted.length; i++)
    sorted[i] = array[indicies[i]];
  return sorted;
}

// The default comparison logic used by Array.sort(), if compareFunction is not provided:
function defaultCompare(a, b) {
  a = String(a);
  b = String(b);
  if (a < b) return -1;
  else if (a > b) return 1;
  else return 0;
}

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

5 голосов
/ 03 сентября 2018

Начиная с V8 v7.0 и Chrome 70, наша реализация Array.prototype.sort теперь стабильна. ?

Ранее V8 использовал нестабильную быструю сортировку для массивов с более чем 10 элементами . Теперь V8 использует стабильный алгоритм TimSort.

Единственный основной движок JavaScript, который все еще имеет нестабильную реализацию Array#sort, - это Chakra, используемый в Microsoft Edge. Чакра использует QuickSort для массивов с более 512 элементов . Для небольших массивов используется стабильная реализация сортировки вставками.

Демо: https://mathiasbynens.be/demo/sort-stability

0 голосов
/ 12 июня 2010

Если вы ищете список браузеров, в которых вы должны использовать не родной алгоритм сортировки, я предлагаю не .

Вместо этого выполните проверку работоспособности сортировки при загрузке сценария и примите решение на основании этого.

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

Вы можете отправить патч на http://www.browserscope.org/, чтобы включить такие тесты в свой набор. Но опять же, функция обнаружения превосходит обнаружение браузера.

...