Ho una serie di stringhe che devo ordinare in JavaScript, ma in modo insensibile alle maiuscole. Come eseguire questo?
Ho una serie di stringhe che devo ordinare in JavaScript, ma in modo insensibile alle maiuscole. Come eseguire questo?
Risposte:
In (quasi :) un one-liner
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Che si traduce in
[ 'bar', 'Foo' ]
Mentre
["Foo", "bar"].sort();
risultati in
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
quando lo localeCompare
fa già di default in alcuni casi. Puoi leggere di più sui parametri per passarci qui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
EDIT: Nota che inizialmente ho scritto questo per illustrare la tecnica piuttosto che avere in mente le prestazioni. Per una soluzione più compatta, consultare anche la risposta @Ivan Krechetov.
toLowerCase
due volte su ogni stringa; sarebbe più efficiente archiviare le versioni ridotte della stringa in variabili.
.toLowerCase()
più volte per ogni elemento dell'array. Ad esempio, 45 chiamate alla funzione di confronto durante l'ordinamento di 10 articoli in ordine inverso. 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
È tempo di rivisitare questa vecchia domanda.
Non utilizzare soluzioni basate su toLowerCase
. Sono inefficienti e semplicemente non funzionano in alcune lingue (ad esempio il turco). Preferisco questo:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Controlla la documentazione per la compatibilità del browser e tutto ciò che c'è da sapere sensitivity
sull'opzione.
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"]
, potremmo desiderare che ritorni ["111", "33"]
perché 1 precede 3 nell'ordinamento del codice carattere. Tuttavia, la funzione in questa risposta tornerà ["33", "111"]
perché il numero 33
è inferiore al numero 111
.
"33" > "111" === true
e 33 > 111 === false
. Funziona come previsto.
È inoltre possibile utilizzare il nuovo Intl.Collator().compare
, per MDN è più efficiente quando si ordinano gli array. Il rovescio della medaglia è che non è supportato dai browser più vecchi. MDN afferma che non è affatto supportato in Safari. È necessario verificarlo, poiché afferma che Intl.Collator
è supportato.
Quando si confrontano un numero elevato di stringhe, ad esempio nell'ordinamento di matrici di grandi dimensioni, è meglio creare un oggetto Intl.Collator e utilizzare la funzione fornita dalla sua proprietà compare
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Se si desidera garantire lo stesso ordine indipendentemente dall'ordine degli elementi nell'array di input, ecco un ordinamento stabile :
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;
});
Normalizza il caso .sort()
con .toLowerCase()
.
Puoi anche usare l'operatore Elvis:
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);
dà:
biscuit,Bob,charley,fudge,Fudge
Il metodo localeCompare probabilmente va bene anche se ...
Nota: l'operatore Elvis è un 'operatore ternario' in forma abbreviata per se poi, di solito con incarico.
Se guardi il?: Lateralmente, sembra Elvis ...
cioè invece di:
if (y) {
x = 1;
} else {
x = 2;
}
Puoi usare:
x = y?1:2;
cioè quando y è vero, quindi restituisce 1 (per l'assegnazione a x), altrimenti restituisce 2 (per l'assegnazione a x).
x = y ? y : z
, puoi farlo x = y ?: z
. Javascript non ha un vero operatore Elvis, ma puoi usarlo x = y || z
in modo simile.
Le altre risposte presuppongono che l'array contenga stringhe. Il mio metodo è migliore, perché funzionerà anche se l'array contiene null, non definito o altre non stringhe.
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;
}
Il null
verranno ordinati tra 'nulk' e 'nulm'. Ma undefined
sarà sempre ordinato per ultimo.
(''+notdefined) === "undefined"
quindi sarebbe
Array.prototype.sort
: | perché la parte su (''+notdefined) === "undefined"
è davvero vera ... il che significa che se capovolgi -1 e 1 nella funzione di ordinamento per invertire l'ordine, undefined ordina comunque fino alla fine. Deve anche essere preso in considerazione quando si utilizza la funzione di confronto al di fuori del contesto di un ordinamento di array (come lo ero quando sono arrivato a questa domanda).
Array.prototype.sort
definizione, abbina più commenti. Innanzitutto, non è necessario che (''+a)
- ECMAScript richieda toString()
di essere richiamato su elementi prima di passarli in compareFn. In secondo luogo, il fatto che ignoreCase
ritorni 1
quando si confrontano stringhe uguali (incluso uguale per maiuscole e minuscole) significa che la specifica non definisce il risultato se ci sono valori duplicati (probabilmente andrà bene solo con alcuni swap non necessari, penso).
undefined
sia un caso speciale, che per ogni x x <indefinito e x> indefinito sono entrambi falsi . Questo undefined
è sempre l'ultimo, è un sottoprodotto dell'implementazione dell'ordinamento dell'ordinamento. Ho provato a cambiare ('' + a) in semplicemente a, ma non ci riesce. ho capito TypeError: a.toUpperCase is not a function
. Apparentemente nontoString
viene chiamato prima di chiamare compareFn.
undefined
il compareFn non
Versione ES6:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
A sostegno della risposta accettata, vorrei aggiungere che la seguente funzione sembra modificare i valori nell'array originale da ordinare in modo che non solo ordinerà le lettere minuscole, ma anche i valori maiuscoli verranno modificati in lettere minuscole. Questo è un problema per me perché anche se desidero vedere Mary accanto a Mary, non desidero che il caso del primo valore Mary sia cambiato in minuscolo.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
Nei miei esperimenti, la seguente funzione della risposta accettata ordina correttamente ma non cambia i valori.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Questo può aiutare se hai difficoltà a capire:
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;
});
Nella funzione sopra, se confrontiamo solo quando due lettere minuscole valgono aeb, non avremo il risultato grazioso.
Esempio, se array è [A, a, B, b, c, C, D, d, e, E] e utilizziamo la funzione sopra, abbiamo esattamente quell'array. Non è cambiato nulla.
Per avere il risultato è [A, a, B, b, C, c, D, d, E, e], dovremmo confrontare nuovamente quando due valori minuscoli sono uguali:
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;
}
}
}
Ho racchiuso la risposta superiore in un polyfill in modo da poter chiamare .sortIgnoreCase () su array di stringhe
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
Avvolgi le corde / /i
. Questo è un modo semplice per usare regex per ignorare l'involucro