Frage

Ich habe eine Liste von Objekten, die ich nach einem Feld sortieren möchte attr vom Typ string.Ich habe es mit versucht -

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

aber das habe ich gefunden - scheint nicht mit Zeichenfolgen in JavaScript zu funktionieren.Wie kann ich eine Liste von Objekten basierend auf einem Attribut vom Typ String sortieren?

War es hilfreich?

Lösung

Verwenden String.prototype.localeCompare a pro Ihr Beispiel:

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

Wir erzwingen, dass a.attr ein String ist, um Ausnahmen zu vermeiden. localeCompare wurde unterstützt seit Internet Explorer 6 und Firefox 1.Möglicherweise wird auch der folgende Code verwendet, der kein Gebietsschema berücksichtigt:

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

Andere Tipps

Eine aktualisierte Antwort (Oktober 2014)

Ich war wirklich verärgert über diese natürliche Sortierreihenfolge der Zeichenfolgen, also habe ich mir einige Zeit genommen, dieses Problem zu untersuchen.Ich hoffe das hilft.

Um es kurz zu machen

localeCompare() Die Charakterunterstützung ist knallhart, nutzen Sie sie einfach.Wie von hervorgehoben Shog9, die Antwort auf Ihre Frage lautet:

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

In allen benutzerdefinierten Javascript-Implementierungen der „natürlichen Zeichenfolgensortierreihenfolge“ wurden Fehler gefunden

Es gibt eine ganze Reihe benutzerdefinierter Implementierungen, die versuchen, einen String-Vergleich durchzuführen, der genauer gesagt als „natürliche String-Sortierreihenfolge“ bezeichnet wird.

Beim „Spielen“ mit diesen Implementierungen sind mir immer einige seltsame „natürliche Sortierreihenfolgen“ oder vielmehr Fehler (oder Auslassungen im besten Fall) aufgefallen.

Normalerweise werden Sonderzeichen (Leerzeichen, Bindestrich, kaufmännisches Und-Zeichen, Klammern usw.) nicht korrekt verarbeitet.

Sie werden dann feststellen, dass sie an verschiedenen Stellen verwechselt erscheinen. Typischerweise könnte das sein:

  • einige stehen zwischen dem Großbuchstaben „Z“ und dem Kleinbuchstaben „a“.
  • einige stehen zwischen der „9“ und dem Großbuchstaben „A“
  • einige werden nach dem Kleinbuchstaben „z“ stehen

Wenn man erwartet hätte, dass alle Sonderzeichen an einer Stelle „gruppiert“ werden, mit Ausnahme des Leerzeichens vielleicht (das immer das erste Zeichen wäre).Das heißt, entweder alle vor Zahlen oder alle zwischen Zahlen und Buchstaben (Klein- und Großbuchstaben stehen hintereinander) oder alle nach Buchstaben.

Meine Schlussfolgerung ist, dass sie alle keine konsistente Reihenfolge bieten, wenn ich anfange, kaum ungewöhnliche Zeichen hinzuzufügen (z. B.Zeichen mit diakritischen Zeichen oder Zeichen wie Bindestrich, Ausrufezeichen usw.).

Recherche zu den benutzerdefinierten Implementierungen:

Die native „natürliche String-Sortierreihenfolge“-Implementierung des Browsers über localeCompare()

localeCompare() Die älteste Implementierung (ohne die Locales- und Optionsargumente) wird von IE6+ unterstützt, siehe http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx (Scrollen Sie nach unten zur Methode localeCompare()).Der eingebaute localeCompare() Die Methode leistet viel bessere Arbeit beim Sortieren, sogar bei internationalen Zeichen und Sonderzeichen.Das einzige Problem bei der Verwendung von localeCompare() Methode ist das „Das verwendete Gebietsschema und die Sortierreihenfolge hängen vollständig von der Implementierung ab.“Mit anderen Worten, wenn Sie localeCompare wie stringOne.localeCompare(stringTwo) verwenden:Firefox, Safari, Chrome und IE haben eine andere Sortierreihenfolge für Strings.

Recherche zu den browsernativen Implementierungen:

Schwierigkeit der „natürlichen Sortierreihenfolge der Zeichenfolgen“

Implementierung eines soliden Algorithmus (bedeutet:konsistent zu sein, aber auch ein breites Spektrum an Charakteren abzudecken) ist eine sehr schwierige Aufgabe.UTF8 enthält mehr als 2000 Zeichen & deckt mehr als 120 Skripte (Sprachen) ab.Schließlich gibt es noch einige Spezifikationen für diese Aufgabe, den sogenannten „Unicode-Sortierungsalgorithmus“, der unter zu finden ist http://www.unicode.org/reports/tr10/ .Weitere Informationen hierzu finden Sie in dieser Frage, die ich gepostet habe https://softwareengineering.stackexchange.com/questions/257286/is-there-any-lingual-agnostic-pecification-for-string-natural-sorting-order

Schlußfolgerung

Angesichts des aktuellen Unterstützungsniveaus der benutzerdefinierten Javascript-Implementierungen, auf die ich gestoßen bin, werden wir wahrscheinlich nie etwas sehen, das auch nur annähernd die Unterstützung all dieser Zeichen und Skripte (Sprachen) bietet.Daher würde ich lieber die native Methode localeCompare() des Browsers verwenden.Ja, es hat zwar den Nachteil, dass es in allen Browsern nicht konsistent ist, aber grundlegende Tests zeigen, dass es einen viel größeren Bereich an Zeichen abdeckt und solide und aussagekräftige Sortierreihenfolgen ermöglicht.

Also wie von hervorgehoben Shog9, die Antwort auf Ihre Frage lautet:

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

Weiterführende Literatur:

Dank der netten Antwort von Shog9, die mich meiner Meinung nach in die „richtige“ Richtung gebracht hat

Antwort (in modernem ECMAScript)

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

Oder

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

Beschreibung

Die Umwandlung eines booleschen Werts in eine Zahl ergibt Folgendes:

  • true -> 1
  • false -> 0

Betrachten Sie drei mögliche Muster:

  • x ist größer als y: (x > y) - (y < x) -> 1 - 0 -> 1
  • x ist gleich y: (x > y) - (y < x) -> 0 - 0 -> 0
  • x ist kleiner als y: (x > y) - (y < x) -> 0 - 1 -> -1

(Alternative)

  • x ist größer als y: +(x > y) || -(x < y) -> 1 || 0 -> 1
  • x ist gleich y: +(x > y) || -(x < y) -> 0 || 0 -> 0
  • x ist kleiner als y: +(x > y) || -(x < y) -> 0 || -1 -> -1

Diese Logiken entsprechen also typischen Sortierkomparatorfunktionen.

if (x == y) {
    return 0;
}
return x > y ? 1 : -1;

Sie sollten hier > oder < und == verwenden.Die Lösung wäre also:

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

Das hat mich schon lange beschäftigt, also habe ich es endlich recherchiert und Ihnen diesen langatmigen Grund dafür genannt, warum die Dinge so sind, wie sie sind.

Von dem spez:

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)

Nun gehen wir also zu 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.

Das ist es. Der dreifache Gleichheitsoperator, der auf Zeichenfolgen angewendet wird, gibt „true“ zurück, wenn die Argumente genau dieselben Zeichenfolgen sind (gleiche Länge und gleiche Zeichen an entsprechenden Positionen).

Also === funktioniert in den Fällen, in denen wir versuchen, Zeichenfolgen zu vergleichen, die möglicherweise aus verschiedenen Quellen stammen, von denen wir jedoch wissen, dass sie letztendlich dieselben Werte haben werden – ein häufiges Szenario für Inline-Zeichenfolgen in unserem Code.Zum Beispiel, wenn wir eine Variable mit dem Namen haben connection_state, und wir möchten wissen, welcher der folgenden Zustände vorliegt ['connecting', 'connected', 'disconnecting', 'disconnected'] Ist es gerade drin, können wir es direkt nutzen ===.

Aber es gibt noch mehr.Direkt über 11.9.4 gibt es einen kurzen Hinweis:

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.Was jetzt?Extern erhaltene Zeichenfolgen können und werden höchstwahrscheinlich seltsame Unicodey- und unsere sanfte sein === wird ihnen nicht gerecht.Kommt herein localeCompare zur Rettung:

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. 

Wir können jetzt nach Hause gehen.

tl;dr;

Um Zeichenfolgen in Javascript zu vergleichen, verwenden Sie localeCompare;Wenn Sie wissen, dass die Zeichenfolgen keine Nicht-ASCII-Komponenten enthalten, da es sich beispielsweise um interne Programmkonstanten handelt, dann === Funktioniert auch.

Verschachtelte ternäre Pfeilfunktion

(a,b) => (a < b ? -1 : a > b ? 1 : 0)

Bei Ihrer Operation in Ihrer ersten Frage führen Sie die folgende Operation aus:

item1.attr - item2.attr

Angenommen, das sind Zahlen (d. h.item1.attr = "1", item2.attr = "2") Sie können weiterhin den Operator "===" (oder andere strenge Evaluatoren) verwenden, vorausgesetzt, Sie stellen den Typ sicher.Folgendes sollte funktionieren:

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

Wenn sie alphanumerisch sind, verwenden Sie localCompare().

list.sort(function(item1, item2){
    return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
}) 

Wie sie funktionieren, Beispiele:

+('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
<!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>
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top