web-dev-qa-db-fra.com

Quelle est la stabilité de la méthode Array.sort () dans différents navigateurs?

Je sais que la spécification ECMA Script ne spécifie pas quel algorithme utiliser pour trier les tableaux, ni ne précise si le tri doit être stable.

J'ai trouvé ces informations pour Firefox qui spécifie que firefox utilise un tri stable.

Quelqu'un connaît-il IE 6/7/8, Chrome et Safari?

64
Boushley

Depuis ES2019, sort doit être stable. Dans ECMAScript 1ère édition jusqu'à ES2018, il a été autorisé à être instable.

Cas de test simple (ignorez l'en-tête, le deuxième ensemble de nombres doit être séquentiel si le tri du moteur est stable). Remarque: Ce cas de test ne fonctionne pas pour certaines versions de Chrome (techniquement, de V8) qui ont changé d'algorithmes de tri en fonction de la taille du tableau, en utilisant un tri stable pour les petits tableaux mais un unstable pour les tableaux plus grands. ( Détails .) Voir la fin de la question pour une version modifiée qui rend le tableau suffisamment grand pour déclencher le comportement.

Le tri d'IE est stable depuis que je l'ai utilisé (donc IE6). Vérification à nouveau dans IE8 et cela semble toujours être le cas.

Et bien que la page Mozilla vers laquelle vous liez indique que le type de Firefox est stable, je dis définitivement que ce n'était pas toujours le cas avant (et y compris) Firefox 2.0.

Quelques résultats superficiels:

  • IE6 +: stable
  • Firefox <3: instable
  • Firefox> = 3: stable
  • Chrome <70: instable
  • Chrome> = 70: stable
  • Opera <10: instable
  • Opera> = 10: stable
  • Safari 4: stable
  • Edge: instable pour les tableaux longs ( > 512 éléments )

Tous les tests sur Windows.

Voir aussi: Implémentation rapide d'un algorithme de tri stable en javascript

Ce cas de test (modifié à partir de ici ) montrera le problème dans V8 (par exemple, Node v6, Chrome <v70) en s'assurant que le tableau a suffisamment d'entrées pour choisir la méthode de tri "plus efficace", ceci est écrit avec de très vieux moteurs JavaScript à l'esprit, donc sans fonctionnalités modernes:

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");
}
60
Crescent Fresh

Je voudrais partager une astuce que j'utilise régulièrement en C/C++ pour qsort().

Sort () de JS permet de spécifier une fonction de comparaison. Créez un deuxième tableau de la même longueur et remplissez-le avec des nombres croissants à partir de 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;

Ce sont des index dans le tableau d'origine. Nous allons trier le deuxième tableau. Créez une fonction de comparaison personnalisée.

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

Il obtiendra les deux éléments du deuxième tableau: utilisez-les comme index dans les tableaux d'origine et comparez les éléments.

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

Si les éléments se trouvent être égaux, comparez leurs index pour rendre l'ordre stable.

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

Après le sort (), le deuxième tableau contiendrait des index que vous pouvez utiliser pour accéder aux éléments du tableau d'origine dans un ordre de tri stable.

  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;
}

En général, les algorithmes de tri stables ne font que mûrir et nécessitent toujours plus de mémoire supplémentaire par rapport au bon ol 'qsort. Je suppose que c'est pourquoi très peu de spécifications exigent un tri stable.

14
Dummy00001

Depuis la V8 v7.0 et Chrome 70, notre implémentation Array.prototype.sort Est maintenant stable. ????

Auparavant, V8 utilisait un QuickSort instable pour les tableaux avec plus de 10 éléments . Désormais, V8 utilise l'algorithme TimSort stable.

Le seul moteur JavaScript majeur qui a toujours une implémentation instable Array#sort Est Chakra, tel qu'utilisé dans Microsoft Edge. Chakra utilise QuickSort pour les tableaux avec plus de 512 éléments . Pour les tableaux plus petits, il utilise une implémentation de tri par insertion stable.

Démo: https://mathiasbynens.be/demo/sort-stability

5
Mathias Bynens