J'ai un tableau de chaînes que je dois trier en JavaScript, mais sans distinction de casse Comment effectuer cela?
Dans (presque :) un one-liner
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Ce qui résulte en
[ 'bar', 'Foo' ]
Tandis que
["Foo", "bar"].sort();
résulte en
[ 'Foo', 'bar' ]
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
EDIT: .__ Veuillez noter que j’ai initialement écrit ceci pour illustrer la technique plutôt que de penser à la performance. Veuillez également vous référer à la réponse @Ivan Krechetov pour une solution plus compacte.
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a == b) return 0;
if (a > b) return 1;
return -1;
});
Il est temps de revenir sur cette vieille question.
Vous ne devez pas utiliser de solutions reposant sur toLowerCase
. Ils sont inefficient et simplement ne fonctionnent pas dans certaines langues (le turc par exemple). Préfère ceci:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Vérifiez la documentation pour la compatibilité du navigateur et tout ce qu'il y a à savoir sur l'option sensitivity
.
Si vous voulez garantir le même ordre indépendamment de l'ordre des éléments dans le tableau en entrée, voici un tri stable :
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;
});
Vous pouvez également utiliser le nouveau Intl.Collator().compare
, par MDN, c'est plus efficace lors du tri des tableaux. L'inconvénient est qu'il n'est pas supporté par les anciens navigateurs. MDN indique qu'il n'est pas du tout pris en charge dans Safari. Besoin de le vérifier, car il est indiqué que Intl.Collator
est pris en charge.
Lors de la comparaison d'un grand nombre de chaînes, comme lors du tri de grands tableaux, il est préférable de créer un objet Intl.Collator et d'utiliser la fonction fournie par sa propriété compare
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Normalisez le cas dans .sort()
avec .toLowerCase()
.
Les autres réponses supposent que le tableau contient des chaînes. Ma méthode est meilleure, car elle fonctionnera même si le tableau contient null, undefined ou d'autres non-chaînes.
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;
}
La null
sera triée entre 'nulk' et 'nulm'. Mais la undefined
sera toujours trié en dernier.
Vous pouvez également utiliser l'opérateur 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);
Donne:
biscuit,Bob,charley,fudge,Fudge
La méthode localeCompare est probablement bien si ...
Remarque: L'opérateur Elvis est un "opérateur ternaire" abrégé, si if else, généralement avec affectation.
Si vous regardez le?: De côté, cela ressemble à Elvis ...
c'est à dire. au lieu de:
if (y) {
x = 1;
} else {
x = 2;
}
vous pouvez utiliser:
x = y?1:2;
c.-à-d. lorsque y est vrai, retourne 1 (pour l'affectation à x), sinon retourne 2 (pour l'affectation à x).
Cela peut aider si vous avez du mal à comprendre:
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.
***/
J'ai enveloppé la première réponse dans un polyfill afin que je puisse appeler .sortIgnoreCase () sur des tableaux de chaînes
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if( a == b) return 0;
if( a > b) return 1;
return -1;
});
Dans la fonction ci-dessus, si nous comparons simplement lorsque les minuscules deux valeurs a et b, nous n'aurons pas le joli résultat.
Exemple, si le tableau est [A, a, B, b, c, C, D, d, e, E] et que nous utilisons la fonction ci-dessus, nous avons exactement ce tableau. Cela n'a rien changé.
Pour que le résultat soit [A, a, B, b, C, D, d, E, e], comparons à nouveau lorsque deux valeurs minuscules sont égales:
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;
}
}
}