525 votes

Comment trier des chaînes de caractères en JavaScript

J'ai une liste d'objets que je souhaite trier en fonction d'un champ. attr de type chaîne. J'ai essayé d'utiliser -

list.sort(function (a, b) {
    return a.attr - b.attr
})

mais a trouvé que - ne semble pas fonctionner avec les chaînes de caractères en JavaScript. Comment trier une liste d'objets en fonction d'un attribut de type chaîne de caractères ?

1 votes

Voir JavaScript case insensitive string comparison sur stackoverflow.com/questions/2140627/

0 votes

Pour une solution rapide "internationalisée" (en partie seulement, je suppose, car cela ne couvre pas tous les accents du monde), vous pouvez simplement ignorer les accents, c'est-à-dire les supprimer. Ensuite, ne faites que votre comparaison de chaînes de caractères, voir Javascript : remove accents/diacritics in strings sur stackoverflow.com/questions/990904/

2 votes

Il est amusant de constater que Jeff Atwood lui-même a écrit un billet de blog sur ce problème courant en 2007, voir blog.codinghorror.com/sorting-for-humans-natural-sort-order

907voto

Shog9 Points 82052

Utilisez String.prototype.localeCompare a selon votre exemple :

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

Nous forçons a.attr à être une chaîne de caractères pour éviter les exceptions. localeCompare a été soutenu depuis Internet Explorer 6 et Firefox 1. Vous pouvez également voir le code suivant utilisé qui ne respecte pas une locale :

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;

140 votes

Avant que quelqu'un ne fasse la même erreur hâtive que moi, c'est local. e Compare, et non localCompare.

20 votes

La première solution considère que "A" vient après "z" mais avant "Z" car elle effectue une comparaison sur la valeur ASCII du caractère. localeCompare() ne rencontre pas ce problème mais ne comprend pas les chiffres, vous obtiendrez donc [ "1", "10", "2" ] comme avec les comparaisons de tri dans la plupart des langages. Si vous voulez un tri pour votre interface utilisateur, regardez l'algorithme de tri alphanumérique/naturel. stackoverflow.com/questions/4340227/ ou stackoverflow.com/questions/4321829/

2 votes

Notez que localeCompare() n'est pris en charge que par les navigateurs modernes : IE11+ au moment de la rédaction, voir developer.mozilla.org/fr/US/docs/Web/JavaScript/Référence/

15voto

airportyh Points 7912

Vous devez utiliser > ou < et == ici. Donc la solution serait :

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});

1 votes

Par ailleurs, cette méthode ne permet pas de gérer les comparaisons entre chaînes et nombres. Par exemple : 'Z' < 9 (faux), 'Z' > 9 (également faux ??), 'Z' == 9 (également faux !!). NaN stupide en JavaScript...

8voto

Manav Points 3039

Cela me tracassait depuis longtemps, alors j'ai finalement fait des recherches et je vous donne cette longue raison pour expliquer pourquoi les choses sont telles qu'elles sont.

De la spec :

Section 11.9.4   The Strict Equals Operator ( === )

The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows: 
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison 
  rval === lval. (See 11.9.6)

Donc maintenant nous passons à 11.9.6

11.9.6   The Strict Equality Comparison Algorithm

The comparison x === y, where x and y are values, produces true or false. 
Such a comparison is performed as follows: 
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the 
  same sequence of characters (same length and same characters in 
  corresponding positions); otherwise, return false.

C'est tout. L'opérateur triple égal appliqué aux chaînes de caractères renvoie vrai si les arguments sont exactement les mêmes chaînes de caractères (même longueur et mêmes caractères dans les positions correspondantes).

Alors === fonctionnera dans les cas où nous essayons de comparer des chaînes de caractères qui peuvent provenir de sources différentes, mais dont nous savons qu'elles auront finalement les mêmes valeurs - un scénario assez courant pour les chaînes de caractères en ligne dans notre code. Par exemple, si nous avons une variable nommée connection_state et nous souhaitons savoir lequel des états suivants ['connecting', 'connected', 'disconnecting', 'disconnected'] dans laquelle il se trouve actuellement, nous pouvons directement utiliser la fonction === .

Mais il y a plus. Juste au-dessus de 11.9.4, il y a une courte note :

NOTE 4     
  Comparison of Strings uses a simple equality test on sequences of code 
  unit values. There is no attempt to use the more complex, semantically oriented
  definitions of character or string equality and collating order defined in the 
  Unicode specification. Therefore Strings values that are canonically equal
  according to the Unicode standard could test as unequal. In effect this 
  algorithm assumes that both Strings are already in normalized form.

Hmm. Quoi encore ? Les cordes obtenues de l'extérieur peuvent être, et seront très probablement, bizarrement unicodées, et notre doux === ne leur rendra pas justice. Entre localeCompare à la rescousse :

15.5.4.9   String.prototype.localeCompare (that)
    ...
    The actual return values are implementation-defined to permit implementers 
    to encode additional information in the value, but the function is required 
    to define a total ordering on all Strings and to return 0 when comparing
    Strings that are considered canonically equivalent by the Unicode standard. 

Nous pouvons rentrer à la maison maintenant.

tl;dr ;

Pour comparer des chaînes de caractères en javascript, utilisez localeCompare ; si vous savez que les chaînes de caractères n'ont pas de composants non-ASCII parce qu'elles sont, par exemple, des constantes internes du programme, alors === fonctionne également.

0voto

eggmatters Points 117

Dans votre opération de votre question initiale, vous effectuez l'opération suivante :

item1.attr - item2.attr

Donc, en supposant qu'il s'agisse de chiffres (c'est-à-dire item1.attr = "1", item2.attr = "2"), vous pouvez toujours utiliser l'opérateur "===" (ou d'autres évaluateurs stricts) à condition de garantir le type. L'exemple suivant devrait fonctionner :

return parseInt(item1.attr) - parseInt(item2.attr);

S'ils sont alphanumériques, alors utilisez localCompare().

0voto

Ishan Liyanage Points 131

Ma mise en œuvre ultime

var dataArr = {  

"hello": [{
    "id": 114,
    "keyword": "zzzzzz",
    "region": "Korea",
    "supportGroup": "administrators",
    "category": "Category2"
}, {
    "id": 115,
    "keyword": "aaaaa",
    "region": "Japan",
    "supportGroup": "developers",
    "category": "Category2"
}]

};
var sortArray = dataArr['hello'];
sortArray.sort(function(a,b) {
     if ( a.region < b.region )
       return -1;
     if ( a.region > b.region )
       return 1;
     return 0;
 } );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X