sort por ordenar objetos numeros multidimensional fecha array javascript string

por - Cómo ordenar cadenas en JavaScript



sort string javascript (8)

Tengo una lista de objetos que deseo ordenar en función de un campo attr de tipo cadena. Traté de usar -

list.sort(function (a, b) { return a.attr - b.attr })

pero encontró que - no parece funcionar con cadenas en JavaScript. ¿Cómo puedo ordenar una lista de objetos en función de un atributo con tipo de cadena?


Respuesta (en ECMAScript Moderno)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))

O

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))

Descripción

La conversión de un valor booleano a un número produce lo siguiente:

  • true -> 1
  • false -> 0

Considere tres posibles patrones:

  • x es más grande que y: (x > y) - (y < x) -> 1 - 0 -> 1
  • x es igual a y: (x > y) - (y < x) -> 0 - 0 -> 0
  • x es más pequeño que y: (x > y) - (y < x) -> 0 - 1 -> -1

(Alternativa)

  • x es más grande que y: +(x > y) || -(x < y) +(x > y) || -(x < y) -> 1 || 0 1 || 0 -> 1
  • x es igual a y: +(x > y) || -(x < y) +(x > y) || -(x < y) -> 0 || 0 0 || 0 -> 0
  • x es más pequeño que y: +(x > y) || -(x < y) +(x > y) || -(x < y) -> 0 || -1 0 || -1 -> -1

Entonces estas lógicas son equivalentes a las típicas funciones de comparación de ordenación

if (x == y) { return 0; } return x > y ? 1 : -1;


Una respuesta actualizada (octubre 2014)

Estaba realmente molesto por este orden de clasificación natural de cuerdas, así que me tomé un tiempo para investigar este problema. Espero que esto ayude.

Larga historia corta

localeCompare() soporte de caracteres es rudo, solo localeCompare() . Como lo señaló Shog9 , la respuesta a su pregunta es:

return item1.attr.localeCompare(item2.attr);

Errores encontrados en todas las implementaciones de javascript "orden natural de secuencia" personalizadas

Hay un montón de implementaciones personalizadas por ahí, tratando de hacer una comparación de cadenas más precisamente llamada "orden natural de cadenas"

Al "jugar" con estas implementaciones, siempre noté una extraña elección de "orden de clasificación natural", o más bien errores (u omisiones en los mejores casos).

Por lo general, los caracteres especiales (espacio, guión, signo, corchetes, etc.) no se procesan correctamente.

A continuación, encontrará que aparecen mezclados en diferentes lugares, que pueden ser:

  • algunos estarán entre la ''Z'' mayúscula y la ''a'' minúscula
  • algunos estarán entre el ''9'' y la ''A'' mayúscula
  • algunos serán después de minúscula ''z''

Cuando uno hubiera esperado que todos los caracteres especiales se "agruparan" en un solo lugar, excepto el carácter especial de espacio tal vez (que siempre sería el primer carácter). Es decir, ya sea todos los números anteriores, o todos entre números y letras (en mayúsculas y minúsculas "juntos" uno tras otro), o todas las letras posteriores.

Mi conclusión es que todos fallan en proporcionar un orden consistente cuando comienzo a agregar caracteres apenas inusuales (es decir, caracteres con signos diacríticos o caracteres como guiones, signos de exclamación, etc.).

Investigación sobre las implementaciones personalizadas:

Implementaciones nativas del "orden natural de las cadenas" de los localeCompare() través de localeCompare()

localeCompare() implementación más antigua (sin las configuraciones regionales y los argumentos de las opciones) es compatible con IE6 +, consulte msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx (desplácese hacia abajo al método localeCompare ()). El método localeCompare() hace un trabajo mucho mejor en la clasificación, incluso en caracteres internacionales y especiales. El único problema con el método localeCompare() es que code.google.com/p/v8/issues/detail?id=459 code.google.com/p/v8/issues/detail?id=459

Investigación sobre las implementaciones nativas del navegador:

Dificultad de "ordenación natural de la cuerda"

Implementar un algoritmo sólido (es decir, consistente, pero que también cubra una amplia gama de caracteres) es una tarea muy difícil. UTF8 contiene más de 2000 caracteres y cubre más de 120 scripts (idiomas) . Finalmente, hay algunas especificaciones para estas tareas, se llama "Algoritmo de intercalación de Unicode", que se puede encontrar en http://www.unicode.org/reports/tr10/ . Puede encontrar más información sobre esto en esta pregunta que publiqué https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specification-for-string-natural-sorting-order

Conclusión final

Por lo tanto, considerando el nivel actual de soporte provisto por las implementaciones personalizadas de javascript que encontré, probablemente nunca veremos nada que se acerque a soportar todos estos caracteres y scripts (idiomas). Por lo tanto, preferiría usar el método nataleCompare () de los navegadores. Sí, tiene la desventaja de ser no consistente en todos los navegadores, pero las pruebas básicas muestran que cubre una gama mucho más amplia de caracteres, lo que permite un ordenamiento sólido y significativo.

Entonces, como lo señaló Shog9 , la respuesta a tu pregunta es:

return item1.attr.localeCompare(item2.attr);

Otras lecturas:

Gracias a la buena respuesta de Shog9, que me puso en la dirección "correcta", creo.


Debes usar> o <y == aquí. Entonces la solución sería:

list.sort(function(item1, item2) { var val1 = item1.attr, val2 = item2.attr; if (val1 == val2) return 0; if (val1 > val2) return 1; if (val1 < val2) return -1; });


En su operación en su pregunta inicial, está realizando la siguiente operación:

item1.attr - item2.attr

Entonces, suponiendo que sean números (es decir, item1.attr = "1", item2.attr = "2") Aún puede usar el operador "===" (u otros evaluadores estrictos) siempre que se asegure el tipo. Lo siguiente debería funcionar:

return parseInt(item1.attr) - parseInt(item2.attr);

Si son alphaNumeric, entonces use localCompare ().


Me había preocupado por esto por mucho tiempo, así que finalmente investigué esto y te di una razón tan larga por la cual las cosas son como son.

De la spec :

Section 11.9.4 The Strict Equals Operator ( === ) The production EqualityExpression : EqualityExpression === RelationalExpression is evaluated as follows: - Let lref be the result of evaluating EqualityExpression. - Let lval be GetValue(lref). - Let rref be the result of evaluating RelationalExpression. - Let rval be GetValue(rref). - Return the result of performing the strict equality comparison rval === lval. (See 11.9.6)

Así que ahora vamos a 11.9.6

11.9.6 The Strict Equality Comparison Algorithm The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows: - If Type(x) is different from Type(y), return false. - If Type(x) is Undefined, return true. - If Type(x) is Null, return true. - If Type(x) is Number, then ... - If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.

Eso es. El operador de triple igual aplicado a las cadenas devuelve verdadero si los argumentos son exactamente las mismas cadenas (la misma longitud y los mismos caracteres en las posiciones correspondientes).

Por lo tanto, === funcionará en los casos en los que intentemos comparar cadenas que podrían haber llegado de diferentes fuentes, pero que sabemos que eventualmente tendrán los mismos valores, un escenario lo suficientemente común para las cadenas en línea en nuestro código. Por ejemplo, si tenemos una variable llamada connection_state , y deseamos saber en cuál de los siguientes estados [''connecting'', ''connected'', ''disconnecting'', ''disconnected''] está en este momento, podemos usar directamente === .

Pero hay más. Justo por encima de 11.9.4, hay una breve nota:

NOTE 4 Comparison of Strings uses a simple equality test on sequences of code unit values. There is no attempt to use the more complex, semantically oriented definitions of character or string equality and collating order defined in the Unicode specification. Therefore Strings values that are canonically equal according to the Unicode standard could test as unequal. In effect this algorithm assumes that both Strings are already in normalized form.

Hmm ¿Ahora que? Las cadenas obtenidas externamente pueden, y lo más probable es que sean, unicodey extrañas, y nuestro === suave no les hará justicia. En viene localeCompare al rescate:

15.5.4.9 String.prototype.localeCompare (that) ... The actual return values are implementation-defined to permit implementers to encode additional information in the value, but the function is required to define a total ordering on all Strings and to return 0 when comparing Strings that are considered canonically equivalent by the Unicode standard.

Podemos ir a casa ahora.

tl; dr;

Para comparar cadenas en javascript, use localeCompare ; Si sabe que las cadenas no tienen componentes que no sean ASCII porque son, por ejemplo, constantes de programa internas, entonces === también funciona.


Use String.prototype.localeCompare a según su ejemplo:

list.sort(function (a, b) { return ('''' + a.attr).localeCompare(b.attr); })

Forzamos que a.attr sea una cadena para evitar excepciones. localeCompare ha sido compatible desde Internet Explorer 6 y Firefox 1. También puede ver el siguiente código utilizado que no respeta una configuración regional:

if (item1.attr < item2.attr) return -1; if ( item1.attr > item2.attr) return 1; return 0;


<!doctype html> <html> <body> <p id = "myString">zyxtspqnmdba</p> <p id = "orderedString"></p> <script> var myString = document.getElementById("myString").innerHTML; orderString(myString); function orderString(str) { var i = 0; var myArray = str.split(""); while (i < str.length){ var j = i + 1; while (j < str.length) { if (myArray[j] < myArray[i]){ var temp = myArray[i]; myArray[i] = myArray[j]; myArray[j] = temp; } j++; } i++; } var newString = myArray.join(""); document.getElementById("orderedString").innerHTML = newString; } </script> </body> </html>


list.sort(function(item1, item2){ return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1; })

Cómo funcionan las muestras:

+(''aaa''>''bbb'')||+(''aaa''===''bbb'')-1 +(false)||+(false)-1 0||0-1 -1 +(''bbb''>''aaa'')||+(''bbb''===''aaa'')-1 +(true)||+(false)-1 1||0-1 1 +(''aaa''>''aaa'')||+(''aaa''===''aaa'')-1 +(false)||+(true)-1 0||1-1 0