400x Tri Speedup par la Commutation d'un.localeCompare(b) à (a<b?-1:(a>b?1:0))
Par la commutation d'un javascript fonction de tri de
myArray.sort(function (a, b) {
return a.name.localeCompare(b.name);
});
à
myArray.sort(function (a, b) {
return (a.name < b.name ? -1 : (a.name > b.name ? 1 : 0));
});
J'ai été en mesure de réduire le temps de trier un ~1700 élément de tableau dans google Chrome à partir de 1993 millisecondes à 5 millisecondes. Près d'un 400x speedup. Malheureusement, c'est au détriment de l'correctement trier des chaînes en anglais.
Évidemment, je ne peux pas avoir mon INTERFACE de blocage pendant 2 secondes lorsque j'essaie de faire un tri. Est-ce que je peux faire pour éviter les, horriblement lent localeCompare mais encore de maintenir le soutien pour les chaînes localisées?
- Envisager tourne un web worker faire le
localeCompare
de tri de manière asynchrone. Vous trouverez peut-être que le temps passé à la sérialisation et la désérialisation cette quantité de données, l'emportent sur les avantages de le faire de manière asynchrone, mais ça vaut le coup. - Que serais probablement le travail, mais 2 secondes est toujours très lent à afficher les résultats.
- Vous pourriez envisager une approche différente - comme de garder la liste triée dès le début, donc vous ne devez jamais explicitement de tri. D'où viennent les données? Il y a quelques auto-tri des structures de données pour JavaScript déjà mis en place: stackoverflow.com/a/5309821/139010 ou stackoverflow.com/a/3809836/139010
- Il s'agit de Facebook. Nous avons terminé le préchargement et de tri avant qu'ils le nécessaire pour y accéder.
- web les travailleurs ne semble pas gérer les localeCompare de la même façon que le reste du code. Voir cette question
- notez que localeCompare n'est pas sensible à la casse (ou peut-être que ça dépend des utilisateurs régionaux? sur mon pc pour en_US il n'est pas sensible à la casse). Remplacement de votre code est sensible à la casse, "Foo" vient avant "bar"
Vous devez vous connecter pour publier un commentaire.
Une grande amélioration de la performance peut être obtenue en déclarant le collateur de l'objet au préalable et en l'utilisant la méthode de comparaison. Par exemple:
Voici un test du script de la comparaison de 3 méthodes:
JS:
arr2
, ce qui devrait déjà être triée par le test précédent, de sorte que le troisième test est artificiellement plus rapide. Mieux vaut appelerarr.slice().sort(...)
dans chaque test. Mais le plus important, #3 devrait appelertoLocaleLowercase()
sur les paramètres à donner à une comparaison équitable. Sinon, il produit un ordre de tri différent que les deux premiers tests.Une Approche efficace que j'ai trouvé lorsque vous traitez avec /pour la plupart/caractères latins est l'utilisation de l'opérateur à chaque fois que les deux chaînes corresponde à une regex. Par exemple:
/^[\w-.\s,]*$/
C'est beaucoup plus rapide si les deux chaînes correspondent à l'expression, et au pire, il semble être légèrement plus lent que l'aveuglette appel localeCompare.
Exemple ici: http://jsperf.com/operator-vs-localecompage/11
Il est difficile de connaître la manière la plus rapide de tri sans voir les données à trier. Mais jsperf a beaucoup de bons tests montrant les différences de performances entre les types de tri:
http://jsperf.com/javascript-sort/45
http://jsperf.com/sort-algorithms/31
Toutefois, aucun de ces compte pour les chaînes localisées, et j'imagine que il n'y a pas de moyen facile de trier les chaînes localisées et localeCompare est probablement la meilleure solution pour cela.
Regardant mozilla référence est dit:
"Lors de la comparaison d'un grand nombre de chaînes, comme dans le tri des tableaux de grande taille, il est préférable de créer un Intl.Collateur de l'objet et de l'utilisation de la fonction fournie par son comparer propriété."
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
Mais va à l'Intl.Collateur de référence, il montre que la n'est pas le support pour firefox/safari
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator
vous pouvez essayer d'utiliser certaines options de localCompare d'accélérer les performances. Mais je viens de faire un test rapide de changer le niveau de sensibilité et il semble que cela n'améliore pas le rendement:
http://jsperf.com/sort-locale-strings
Essayer de faire le tri en 2 étapes:
localCompare()
: il a maintenant moins de comparaisons à faire, parce que le tableau est principalement triés.Remarque: je pense que
localCompare()
va surtout être appelé avec au moins 1 chaîne qui n'est pas l'anglais. Ainsi, le nombre d'appels àlocalCompare()
avec 2 chaînes en anglais, devrait être considérablement réduit.Voici le code:
Cette solution a l'avantage d'être court et facile à utiliser. Il sera efficace si le tableau contient principalement des chaînes en anglais. Le plus non-anglais chaînes que vous avez, la moins utile le premier tri sera. Mais comme il est facile d'ajouter dans vos scripts, il est également facile de voir si cette approche est mériteraient.
Maintenant, si j'étais vous, je voudrais aussi utiliser un
Intl.Collateur
, comme il est dit d'être beaucoup plus rapide quelocalCompare()
quand vous avez beaucoup de comparaisons à faire.Je ne sais pas vous toujours à la recherche de solution à ce problème
j'ai ajouté un
=== 1
vérifier votre code et cette amélioration de la perf 400x qui signifie à la fois avoir les mêmes perf numéros.Perf numéros avec localeCompare arr taille: 3200
Avg temps a pris 10 répétitions : 60 ms
Perf numéros avec > approche. avg temps a 55 ms
localeCompare()
peut retourner des valeurs différent de -1, 0 ou 1. Regarder les doc. Aussi, je doute fortement que l'ajout d'une multiplication est plus rapide que ne pas en avoir. Vous devriez faire 2 comparateurs: l'un pour l'ascension, l'un pour l'ordre décroissant. L'équipe sera en mesure de l'inclure beaucoup mieux.