J'ai un tableau de chaînes que je dois trier en JavaScript, mais de manière non sensible à la casse. Comment faire ça?
J'ai un tableau de chaînes que je dois trier en JavaScript, mais de manière non sensible à la casse. Comment faire ça?
Réponses:
Dans (presque :) un one-liner
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Ce qui se traduit par
[ 'bar', 'Foo' ]
Tandis que
["Foo", "bar"].sort();
résulte en
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
alors localeCompare
que cela se fait déjà par défaut dans certains cas. Vous pouvez en savoir plus sur les paramètres à lui transmettre ici: 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: Veuillez noter que j'ai écrit à l'origine pour illustrer la technique plutôt que d'avoir à l'esprit la performance. Veuillez également vous référer à la réponse @Ivan Krechetov pour une solution plus compacte.
toLowerCase
deux fois sur chaque chaîne; serait plus efficace pour stocker des versions réduites de la chaîne dans des variables.
.toLowerCase()
plusieurs fois pour chaque élément du tableau. Par exemple, 45 appels à la fonction de comparaison lors du tri de 10 éléments dans l'ordre inverse. 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
Il est temps de revenir sur cette vieille question.
Vous ne devez pas utiliser de solutions sur lesquelles vous vous fondez toLowerCase
. Ils sont inefficaces et ne fonctionnent tout simplement pas dans certaines langues (turc par exemple). Préférez ceci:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Consultez la documentation pour la compatibilité du navigateur et tout ce qu'il y a à savoir sur l' sensitivity
option.
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"]
, nous pourrions souhaiter qu'il revienne ["111", "33"]
car 1 précède 3 dans l'ordre des codes de caractères. Cependant, la fonction dans cette réponse retournera ["33", "111"]
car le nombre 33
est inférieur au nombre 111
.
"33" > "111" === true
et 33 > 111 === false
. Cela fonctionne comme prévu.
Vous pouvez également utiliser le nouveau Intl.Collator().compare
, par MDN, il est plus efficace lors du tri des tableaux. L'inconvénient est qu'il n'est pas pris en charge par les anciens navigateurs. MDN déclare qu'il n'est pas du tout pris en charge dans Safari. Besoin de le vérifier, car il indique que cela Intl.Collator
est pris en charge.
Lors de la comparaison d'un grand nombre de chaînes, comme dans le 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"]
Si vous souhaitez garantir le même ordre quel que soit l'ordre des éléments dans le tableau d'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;
});
Normaliser le cas dans le .sort()
avec .toLowerCase()
.
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 très bien cependant ...
Remarque: L'opérateur Elvis est un «opérateur ternaire» abrégé pour if if else, généralement avec affectation.
Si vous regardez le?: De côté, il ressemble à Elvis ...
c'est-à-dire au lieu de:
if (y) {
x = 1;
} else {
x = 2;
}
vous pouvez utiliser:
x = y?1:2;
c'est-à-dire quand y est vrai, alors retourne 1 (pour l'affectation à x), sinon retourne 2 (pour l'affectation à x).
x = y ? y : z
, vous pouvez le faire x = y ?: z
. Javascript n'a pas d'opérateur Elvis réel, mais vous pouvez l'utiliser x = y || z
de manière similaire.
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;
}
Le null
sera trié entre «nulk» et «nulm». Mais le undefined
sera toujours trié en dernier.
(''+notdefined) === "undefined"
il
Array.prototype.sort
: | parce que la partie sur (''+notdefined) === "undefined"
est vraiment vraie ... ce qui signifie que si vous inversez les -1 et 1 dans la fonction de tri pour inverser l'ordre, les tris non définis continuent jusqu'à la fin. Il doit également être pris en compte lors de l'utilisation de la fonction de comparaison en dehors du contexte d'un tri de tableau (comme je l'étais lorsque je suis tombé sur cette question).
Array.prototype.sort
définition - quelques commentaires supplémentaires. Tout d'abord, il n'est pas nécessaire que (''+a)
- ECMAScript nécessite toString()
d'être appelé sur les éléments avant de les passer dans compareFn. Deuxièmement, le fait que ignoreCase
renvoie 1
lors de la comparaison de chaînes égales (y compris les chaînes égales mais pour le cas) signifie que la spécification ne définit pas le résultat s'il y a des valeurs en double (ce sera probablement bien juste avec des échanges inutiles, je pense).
undefined
c'est un cas particulier qui, pour tout x x <undefined et x> undefined, est à la fois faux . C'est undefined
toujours le dernier, est un sous-produit de l'implémentation de tri de sorte. J'ai essayé de changer le ('' + a) en un simple, mais cela échoue. je reçois TypeError: a.toUpperCase is not a function
. Apparemment, il toString
n'est pas appelé avant d'appeler compareFn.
undefined
le compareFn n'est jamais appelé
Version ES6:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
À l'appui de la réponse acceptée, je voudrais ajouter que la fonction ci-dessous semble changer les valeurs du tableau d'origine à trier de sorte que non seulement elle triera les minuscules, mais les valeurs en majuscules seront également modifiées en minuscules. C'est un problème pour moi car même si je souhaite voir Marie à côté de marie, je ne souhaite pas que le cas de la première valeur Mary soit changé en minuscule.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
Dans mes expériences, la fonction suivante de la réponse acceptée trie correctement mais ne change pas les valeurs.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Cela peut être utile 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.
***/
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 deux valeurs minuscules 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 avoir le résultat est [A, a, B, b, C, c, D, d, E, e], nous devons comparer à 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;
}
}
}
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());
});
};
}
Enveloppez vos cordes / /i
. C'est un moyen facile d'utiliser l'expression régulière pour ignorer le boîtier