Ich habe eine Reihe von Zeichenfolgen, die ich in JavaScript sortieren muss, jedoch ohne Berücksichtigung der Groß- und Kleinschreibung. Wie führe ich das durch?
Ich habe eine Reihe von Zeichenfolgen, die ich in JavaScript sortieren muss, jedoch ohne Berücksichtigung der Groß- und Kleinschreibung. Wie führe ich das durch?
Antworten:
In (fast :) einem Einzeiler
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Was in ... endet
[ 'bar', 'Foo' ]
Während
["Foo", "bar"].sort();
führt zu
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
wenn localeCompare
dies in einigen Fällen bereits standardmäßig erfolgt. Weitere
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
EDIT: Bitte beachten Sie, dass ich dies ursprünglich geschrieben habe, um die Technik zu veranschaulichen, anstatt die Leistung im Auge zu behalten. Eine kompaktere Lösung finden Sie auch in der Antwort @Ivan Krechetov.
toLowerCase
zweimal für jede Zeichenfolge aufgerufen werden. Es wäre effizienter, abgesenkte Versionen der Zeichenfolge in Variablen zu speichern.
.toLowerCase()
mehrmals für jedes Element im Array aufrufen . Zum Beispiel rufen 45 die Vergleichsfunktion auf, wenn 10 Elemente in umgekehrter Reihenfolge sortiert werden. var i = 0; ["z","y","x","w","v","u","t","s","r","q"].sort(function (a, b) {++i; return a.toLowerCase().localeCompare(b.toLowerCase());}); console.log("Calls to Compare: " + i); // i === 45
Es ist Zeit, diese alte Frage erneut zu prüfen.
Sie sollten keine Lösungen verwenden, auf die Sie sich verlassen können toLowerCase
. Sie sind ineffizient und funktionieren in einigen Sprachen (z. B. Türkisch) einfach nicht . Bevorzugen Sie dies:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Überprüfen Sie die Dokumentation auf Browserkompatibilität und alles, was Sie über die sensitivity
Option wissen müssen .
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a == b) return 0;
if (a > b) return 1;
return -1;
});
return a === b ? 0 : a > b ? 1 : -1;
["111", "33"]
, möchten wir möglicherweise, dass es zurückgegeben wird, ["111", "33"]
da 1 in der Reihenfolge der Zeichencodes vor 3 steht. Die Funktion in dieser Antwort wird jedoch zurückgegeben, ["33", "111"]
da die Nummer 33
kleiner als die Nummer ist 111
.
"33" > "111" === true
und 33 > 111 === false
. Es funktioniert wie vorgesehen.
Sie können auch das neue verwenden Intl.Collator().compare
, das pro MDN beim Sortieren von Arrays effizienter ist . Der Nachteil ist, dass es von älteren Browsern nicht unterstützt wird. MDN gibt an, dass es in Safari überhaupt nicht unterstützt wird. Muss überprüft werden, da es besagt, dassIntl.Collator
unterstützt wird.
Wenn Sie eine große Anzahl von Zeichenfolgen vergleichen, z. B. beim Sortieren großer Arrays, ist es besser, ein Intl.Collator-Objekt zu erstellen und die durch die compare-Eigenschaft bereitgestellte Funktion zu verwenden
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Wenn Sie unabhängig von der Reihenfolge der Elemente im Eingabearray dieselbe Reihenfolge garantieren möchten, finden Sie hier eine stabile Sortierung:
myArray.sort(function(a, b) {
/* Storing case insensitive comparison */
var comparison = a.toLowerCase().localeCompare(b.toLowerCase());
/* If strings are equal in case insensitive comparison */
if (comparison === 0) {
/* Return case sensitive comparison instead */
return a.localeCompare(b);
}
/* Otherwise return result */
return comparison;
});
Normalisieren Sie den Fall in der .sort()
mit .toLowerCase()
.
Sie können auch den Elvis-Operator verwenden:
arr = ['Bob', 'charley', 'fudge', 'Fudge', 'biscuit'];
arr.sort(function(s1, s2){
var l=s1.toLowerCase(), m=s2.toLowerCase();
return l===m?0:l>m?1:-1;
});
console.log(arr);
Gibt:
biscuit,Bob,charley,fudge,Fudge
Die localeCompare-Methode ist wahrscheinlich in Ordnung ...
Hinweis: Der Elvis-Operator ist eine Kurzform 'ternärer Operator', wenn sonst, normalerweise mit Zuweisung.
Wenn Sie das ?: Seitwärts betrachten, sieht es aus wie Elvis ...
dh anstelle von:
if (y) {
x = 1;
} else {
x = 2;
}
Sie können verwenden:
x = y?1:2;
dh wenn y wahr ist, geben Sie 1 zurück (für die Zuordnung zu x), andernfalls geben Sie 2 zurück (für die Zuordnung zu x).
x = y ? y : z
können Sie dies tun x = y ?: z
. Javascript hat keinen tatsächlichen Elvis-Operator, aber Sie können ihn x = y || z
auf ähnliche Weise verwenden.
Die anderen Antworten setzen voraus, dass das Array Zeichenfolgen enthält. Meine Methode ist besser, da sie auch dann funktioniert, wenn das Array null, undefinierte oder andere Nicht-Zeichenfolgen enthält.
var notdefined;
var myarray = ['a', 'c', null, notdefined, 'nulk', 'BYE', 'nulm'];
myarray.sort(ignoreCase);
alert(JSON.stringify(myarray)); // show the result
function ignoreCase(a,b) {
return (''+a).toUpperCase() < (''+b).toUpperCase() ? -1 : 1;
}
Das null
wird zwischen 'nulk' und 'nulm' sortiert. Aber das undefined
wird immer zuletzt sortiert.
(''+notdefined) === "undefined"
also würde es vor "z" sortieren
Array.prototype.sort
: | nachschlagen sollen weil der Teil über (''+notdefined) === "undefined"
wirklich wahr ist ... was bedeutet, wenn Sie -1 und 1 in der Sortierfunktion umdrehen, um die Reihenfolge umzukehren, wird undefined immer noch bis zum Ende sortiert. Dies muss auch berücksichtigt werden, wenn die Vergleichsfunktion außerhalb des Kontexts einer Array-Sortierung verwendet wird (wie ich es war, als ich auf diese Frage stieß).
Array.prototype.sort
Definition nachgedacht habe - noch ein paar Kommentare. Erstens muss das (''+a)
- ECMAScript toString()
nicht für Elemente aufgerufen werden, bevor sie an compareFn übergeben werden. Zweitens ist die Tatsache , dass ignoreCase
Erträge , 1
wenn (einschließlich der Gleich-but-für-Fall) Strings gleich Vergleich bedeutet die Spezifikation das Ergebnis nicht definieren , wenn es doppelte Werte sind (wahrscheinlich in Ordnung sein nur mit einigen unnötigen Swaps auftritt, glaube ich).
undefined
ein Sonderfall ist, der für jedes x x <undefiniert und x> undefiniert beide falsch ist . Das undefined
ist immer das Letzte, ist ein Nebenprodukt der Sortierimplementierung von sort. Ich habe versucht, das ('' + a) einfach in a zu ändern, aber es schlägt fehl. Ich verstehe TypeError: a.toUpperCase is not a function
. Offenbar toString
wird nicht vor dem Aufruf von compareFn genannt.
undefined
den Vergleich wird Fn nie genannt
ES6-Version:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
Zur Unterstützung der akzeptierten Antwort möchte ich hinzufügen, dass die folgende Funktion die Werte im zu sortierenden Original-Array so zu ändern scheint, dass nicht nur Kleinbuchstaben, sondern auch Großbuchstaben in Kleinbuchstaben sortiert werden. Dies ist ein Problem für mich, denn obwohl ich Mary neben Mary sehen möchte, möchte ich nicht, dass der Fall des ersten Wertes Mary in Kleinbuchstaben geändert wird.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
In meinen Experimenten sortiert die folgende Funktion aus der akzeptierten Antwort korrekt, ändert jedoch die Werte nicht.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Dies kann hilfreich sein, wenn Sie Schwierigkeiten haben, Folgendes zu verstehen:
var array = ["sort", "Me", "alphabetically", "But", "Ignore", "case"];
console.log('Unordered array ---', array, '------------');
array.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
console.log("Compare '" + a + "' and '" + b + "'");
if( a == b) {
console.log('Comparison result, 0 --- leave as is ');
return 0;
}
if( a > b) {
console.log('Comparison result, 1 --- move '+b+' to before '+a+' ');
return 1;
}
console.log('Comparison result, -1 --- move '+a+' to before '+b+' ');
return -1;
});
console.log('Ordered array ---', array, '------------');
// return logic
/***
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
***/
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if( a == b) return 0;
if( a > b) return 1;
return -1;
});
Wenn wir in der obigen Funktion nur vergleichen, wenn Kleinbuchstaben zwei Werte a und b sind, haben wir nicht das hübsche Ergebnis.
Beispiel: Wenn das Array [A, a, B, b, c, C, D, d, e, E] ist und wir die obige Funktion verwenden, haben wir genau dieses Array. Es hat nichts geändert.
Um das Ergebnis [A, a, B, b, C, c, D, d, E, e] zu erhalten, sollten wir erneut vergleichen, wenn zwei Kleinbuchstaben gleich sind:
function caseInsensitiveComparator(valueA, valueB) {
var valueALowerCase = valueA.toLowerCase();
var valueBLowerCase = valueB.toLowerCase();
if (valueALowerCase < valueBLowerCase) {
return -1;
} else if (valueALowerCase > valueBLowerCase) {
return 1;
} else { //valueALowerCase === valueBLowerCase
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
}
}
Ich habe die oberste Antwort in eine Polyfüllung gefüllt, damit ich .sortIgnoreCase () für String-Arrays aufrufen kann
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
Wickeln Sie Ihre Saiten ein / /i
. Dies ist eine einfache Möglichkeit, Regex zu verwenden, um das Gehäuse zu ignorieren