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

j'ai une liste d'objets que je souhaite trier basée sur 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 des chaînes en JavaScript. Comment trier une liste d'objets basée sur un attribut avec type string?

228
demandé sur royhowie 2008-09-09 07:25:15

8 réponses

utiliser String.prototype.localeCompare a pour votre exemple:

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

On force une.attr être une chaîne pour éviter les exceptions. localeCompare a été pris en charge 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;
392
répondu Shog9 2018-05-28 22:35:45

une réponse mise à jour (octobre 2014)

j'ai été vraiment ennuyé par cette chaîne de tri naturel ordre donc j'ai pris un certain temps pour enquêter sur cette question. J'espère que cette aide.

longue histoire courte

localeCompare() le support des caractères est un dur, utilisez-le. Comme indiqué par Shog9 , la réponse à votre question Est:

return item1.attr.localeCompare(item2.attr);

Bugs trouvés dans tout le JavaScript personnalisé " naturel ordre de tri des chaînes de caractères" implémentations

il y a tout un tas d'implémentations personnalisées là-bas, essayant de faire une comparaison de chaîne plus précisément appelée "ordre de tri de chaîne naturelle"

en " jouant "avec ces implémentations, j'ai toujours remarqué un étrange choix" d'ordre naturel de tri", ou plutôt des erreurs (ou des omissions dans les meilleurs cas).

typiquement, des caractères spéciaux (Espace, tiret, ampère, crochets, et ainsi de suite)) ne sont pas correctement traités.

vous les trouverez alors mélangés dans différents endroits, typiquement qui pourrait être:

  • certains seront entre les majuscules "Z" et les minuscules "a
  • certains seront entre le " 9 "et le majuscule" A "
  • certains seront après " z " minuscule 1519310920"

alors qu'on aurait pu s'attendre à ce que des caractères spéciaux soient regroupés en un même endroit, sauf pour l'espace caractère spécial peut-être (qui veut toujours être le premier caractère). C'est-à-dire, soit tous avant les chiffres, soit tous entre les chiffres et les lettres (minuscules et majuscules étant "ensemble" l'un après l'autre), ou tous après les lettres.

ma conclusion est qu'ils ne parviennent pas tous à fournir un ordre cohérent quand je commence à ajouter à peine des caractères inhabituels (i.e. caractères avec des signes diacritiques ou des caractères tels que tiret, point d'exclamation et ainsi de suite).

recherche sur les implémentations personnalisées:

Navigateurs " d'origine "naturelle de la chaîne de l'ordre de tri" des implémentations par localeCompare()

localeCompare() la plus ancienne implémentation (sans les arguments locales et options) est supportée par IE6+, voir http://msdn.microsoft.com/en-us/library/ie/s4esdbwz (v=94).aspx (faites défiler jusqu'à la méthode localeCompare ()). La méthode localeCompare() intégrée fait un bien meilleur travail de tri, même les caractères internationaux et spéciaux. Le seul problème à l'aide de la La méthode localeCompare() est que "l'ordre de localisation et de tri utilisé dépend entièrement de la mise en œuvre". En d'autres termes, en utilisant localeCompare tel que stringOne.localeCompare (stringTwo): Firefox, Safari, Chrome & IE ont un ordre de tri différent pour les chaînes.

recherche sur le navigateur-implémentations natives:

difficulté de "chaîne ordre de tri naturel"

mettre en œuvre un algorithme solide (c'est-à-dire cohérent, mais couvrant également une large gamme de caractères) est une tâche très difficile. UTF8 contient plus de 2000 caractères & couvre plus de 120 scripts (langues) . Enfin, il existe certaines spécifications pour ces tâches, il est appelé "algorithme de Collation Unicode", qui peut être trouvé à http://www.unicode.org/reports/tr10 / . Vous pouvez trouver plus d'informations à ce sujet sur cette question j'ai posté /q/comparing-char-which-holds-hex-values-c-24173/"/q/comparing-char-which-holds-hex-values-c-24173/">/q/comparing-char-which-holds-hex-values-c-24173/"/q/how-to-sort-strings-in-javascript-70021/">Comment faites-vous la comparaison de chaîne dans JavaScript?

  • Javascript : naturel tri des chaînes alphanumériques
  • Tri tableau d'éléments numériques et alphabétiques (tri naturel)
  • Tri mixte alpha / tableau numérique
  • https://web.archive.org/web/20130929122019/http://my.opera.com/GreyWyvern/blog/show.dml/1671288
  • https://web.archive.org/web/20131005224909/http://www.davekoelle.com/alphanum.html
  • http://snipplr.com/view/36012/javascript-natural-sort/
  • http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
  • grâce à la réponse sympathique de Shog9, qui m'a mis dans la "bonne" direction je crois

    115
    répondu Adrien Be 2017-05-23 11:55:07

    réponse la plus simple avec ECMAScript 2016

    list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))
    

    ou

    list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))
    
    12
    répondu mpyw 2017-07-07 03:59:03

    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;
    });
    
    7
    répondu airportyh 2016-12-03 18:04:21

    j'avais été tracassé à ce sujet pendant longtemps, donc j'ai finalement cherché ceci et vous donner cette longue raison essoufflée pour pourquoi les choses sont comme 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 allons à 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 ça. l'opérateur Triple equals appliqué aux chaînes renvoie true iff les arguments sont exactement les mêmes chaînes (même longueur et même caractères dans les positions correspondantes).

    donc === fonctionnera dans les cas où nous essayons de comparer des chaînes qui pourraient être arrivées de différentes sources, mais dont nous savons qu'elles auront éventuellement les mêmes valeurs - un scénario assez commun pour les chaînes inline dans notre code. Par exemple, si nous avons une variable nommée connection_state , et que nous voulons savoir dans lequel des états suivants ['connecting', 'connected', 'disconnecting', 'disconnected'] est-il en ce moment, nous pouvons directement utiliser le === .

    mais il y a plus. Juste au-dessus du 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. Que faire maintenant? Les cordes obtenues de l'extérieur peuvent, et probablement le seront, être étranges unicodey, et notre doux === ne leur rendra pas justice. En vient 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. 
    

    on peut rentrer chez nous.

    tl; dr;

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

    4
    répondu Manav 2013-02-07 18:06:20
    <!doctype html>
    <html>
    <body>
    <p id = "myString">zyxtspqnmdba</p>
    <p id = "orderedString"></p>
    <script>
    var myString = document.getElementById("myString").innerHTML;
    orderString(myString);
    function orderString(str) {
        var i = 0;
        var myArray = str.split("");
        while (i < str.length){
            var j = i + 1;
            while (j < str.length) {
                if (myArray[j] < myArray[i]){
                    var temp = myArray[i];
                    myArray[i] = myArray[j];
                    myArray[j] = temp;
                }
                j++;
            }
            i++;
        }
        var newString = myArray.join("");
        document.getElementById("orderedString").innerHTML = newString;
    }
    </script>
    </body>
    </html>
    
    1
    répondu Julio Munoz 2018-04-23 20:45:28

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

    item1.attr - item2.attr
    

    donc, en supposant qu'il s'agit de nombres (c.-à-d. item 1.attr = "1", item2.attr = "2") Vous pouvez toujours utiliser l'opérateur "= = = " (ou d'autres évaluateurs stricts) pourvu que vous assuriez le type.

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

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

    0
    répondu eggmatters 2013-10-24 18:15:33
    list.sort(function(item1, item2){
        return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
    }) 
    

    Comment ils échantillons de travail:

    +('aaa'>'bbb')||+('aaa'==='bbb')-1
    +(false)||+(false)-1
    0||0-1
    -1
    
    +('bbb'>'aaa')||+('bbb'==='aaa')-1
    +(true)||+(false)-1
    1||0-1
    1
    
    +('aaa'>'aaa')||+('aaa'==='aaa')-1
    +(false)||+(true)-1
    0||1-1
    0
    
    0
    répondu Petr Varyagin 2018-01-07 11:43:34