Tengo una serie de cadenas que necesito ordenar en JavaScript, pero sin distinción entre mayúsculas y minúsculas. ¿Cómo realizar esto?
Tengo una serie de cadenas que necesito ordenar en JavaScript, pero sin distinción entre mayúsculas y minúsculas. ¿Cómo realizar esto?
Respuestas:
En (casi :) una línea
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Lo que resulta en
[ 'bar', 'Foo' ]
Mientras
["Foo", "bar"].sort();
resultados en
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
cuando localeCompare
ya lo hace de forma predeterminada en algunos casos. Puede leer más sobre los parámetros para pasar aquí: 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;
}
);
EDITAR: Tenga en cuenta que originalmente escribí esto para ilustrar la técnica en lugar de tener en cuenta el rendimiento. Consulte también la respuesta @Ivan Krechetov para obtener una solución más compacta.
toLowerCase
dos veces en cada cadena; Sería más eficiente almacenar versiones reducidas de la cadena en variables.
.toLowerCase()
varias veces para cada elemento del conjunto. Por ejemplo, 45 llamadas a la función de comparación al ordenar 10 elementos en orden 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
Es hora de revisar esta vieja pregunta.
No debe usar soluciones confiables toLowerCase
. Son ineficientes y simplemente no funcionan en algunos idiomas (turco, por ejemplo). Prefiero esto:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Consulte la documentación de compatibilidad del navegador y todo lo que hay que saber sobre la sensitivity
opción.
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"]
, podríamos querer que vuelva ["111", "33"]
porque 1 viene antes que 3 en el orden del código de caracteres. Sin embargo, la función en esta respuesta volverá ["33", "111"]
porque el número 33
es menor que el número 111
.
"33" > "111" === true
y 33 > 111 === false
. Funciona según lo previsto.
También puede usar el nuevo Intl.Collator().compare
, según MDN, es más eficiente al ordenar matrices. La desventaja es que no es compatible con navegadores antiguos. MDN afirma que no es compatible en absoluto en Safari. Es necesario verificarlo, ya que indica que Intl.Collator
es compatible.
Al comparar grandes cantidades de cadenas, como al ordenar grandes matrices, es mejor crear un objeto Intl.Collator y usar la función proporcionada por su propiedad de comparación
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Si desea garantizar el mismo orden independientemente del orden de los elementos en la matriz de entrada, aquí hay una clasificación estable :
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;
});
Normalizar el caso en el .sort()
con .toLowerCase()
.
También puede usar el operador de 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);
Da:
biscuit,Bob,charley,fudge,Fudge
Sin embargo, el método localeCompare probablemente esté bien ...
Nota: El operador de Elvis es una forma abreviada de 'operador ternario' para si, de lo contrario, generalmente con asignación.
Si miras el?: De lado, se parece a Elvis ...
es decir, en lugar de:
if (y) {
x = 1;
} else {
x = 2;
}
puedes usar:
x = y?1:2;
es decir, cuando y es verdadero, luego devuelve 1 (para la asignación a x), de lo contrario devuelve 2 (para la asignación a x).
x = y ? y : z
, puede hacerlo x = y ?: z
. Javascript no tiene un operador real de Elvis, pero puede usarlo x = y || z
de manera similar.
Las otras respuestas suponen que la matriz contiene cadenas. Mi método es mejor, porque funcionará incluso si la matriz contiene nulos, indefinidos u otras cadenas.
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;
}
El null
se ordenará entre 'nulk' y 'nulm'. Sin embargo, el undefined
será siempre ordenados pasado.
(''+notdefined) === "undefined"
así que se
Array.prototype.sort
: | porque la parte acerca de (''+notdefined) === "undefined"
realmente es verdadera ... lo que significa que si volteas el -1 y el 1 en la función de clasificación para revertir el orden, undefined aún se ordena hasta el final. También debe tenerse en cuenta al usar la función de comparación fuera del contexto de una ordenación de matriz (como lo hice cuando me encontré con esta pregunta).
Array.prototype.sort
definición, un par de comentarios más. Primero, no hay necesidad de (''+a)
- ECMAScript requiere toString()
que se llame a elementos antes de pasarlos a compareFn. En segundo lugar, el hecho de que ignoreCase
regrese 1
al comparar cadenas iguales (incluidas las cadenas iguales pero para el caso) significa que la especificación no define el resultado si hay valores duplicados (creo que probablemente estará bien solo con algunos intercambios innecesarios, creo).
undefined
es un caso especial, que para cualquier x x <undefined y x> undefined son falsos . Eso undefined
siempre es el último, es un subproducto de la implementación del tipo de clasificación. Intenté cambiar el ('' + a) a simplemente a, pero falla. me sale TypeError: a.toUpperCase is not a function
. Al parecer toString
se no llama antes de llamar compareFn.
undefined
el compareFn nunca se llama
Versión ES6:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
En apoyo de la respuesta aceptada, me gustaría agregar que la función a continuación parece cambiar los valores en la matriz original que se ordenará, de modo que no solo clasificará en minúsculas sino que los valores en mayúsculas también se cambiarán a minúsculas. Esto es un problema para mí porque, aunque deseo ver a Mary junto a Mary, no deseo que el caso del primer valor Mary se cambie a minúsculas.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
En mis experimentos, la siguiente función de la respuesta aceptada se ordena correctamente pero no cambia los valores.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Esto puede ayudar si le ha costado entender:
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;
});
En la función anterior, si solo comparamos cuando dos minúsculas valoran a y b, no tendremos el resultado bonito.
Ejemplo, si la matriz es [A, a, B, b, c, C, D, d, e, E] y usamos la función anterior, tenemos exactamente esa matriz. No ha cambiado nada.
Para obtener el resultado es [A, a, B, b, C, c, D, d, E, e], debemos comparar nuevamente cuando dos valores en minúscula son iguales:
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;
}
}
}
Envolví la respuesta superior en un polyfill para poder llamar a .sortIgnoreCase () en matrices de cadenas
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
Envuelve tus cuerdas / /i
. Esta es una manera fácil de usar expresiones regulares para ignorar la carcasa