Estoy buscando la forma más fácil de ordenar una matriz que consta de números y texto, y una combinación de estos.

P.ej

'123asd' '19asd' '12345asd' 'asd123' 'asd12' 

se convierte en

 '19asd' '123asd' '12345asd' 'asd12' 'asd123' 

Esto se usará en combinación con la solución a otra pregunta que he hecho aquí .

La función de clasificación en sí misma funciona, lo que necesito es una función que pueda decir que ’19asd’ es más pequeño que ‘123asd’.

Estoy escribiendo esto en JavaScript.

Editar: como señaló adormitu , lo que estoy buscando es una función para la clasificación natural

Esto ahora es posible en los navegadores modernos que usan localeCompare. Al pasar la opción numeric: true , reconocerá inteligentemente los números. Puede hacer mayúsculas y minúsculas usando sensitivity: 'base' . Probado en Chrome, Firefox e IE11.

Aquí hay un ejemplo. Devuelve 1 , lo que significa que 10 va después de 2:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

Para el rendimiento al ordenar grandes cantidades de cadenas, el artículo dice:

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. Enlace de documentos

 var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'}); var myArray = ['1_Document', '11_Document', '2_Document']; console.log(myArray.sort(collator.compare)); 

Entonces, ¿necesitas un tipo natural ?

Si es así, entonces quizás este guión de Brian Huisman basado en el trabajo de David Koelle sería lo que necesita.

Parece que la solución de Brian Huisman ahora está alojada directamente en el blog de David Koelle:

Para comparar valores, puede usar un método de comparación:

 function naturalSorter(as, bs){ var a, b, a1, b1, i= 0, n, L, rx=/(.d )|(d (.d )?)|([^d.] )|(.D )|(.$)/g; if(as=== bs) return 0; a= as.toLowerCase().match(rx); b= bs.toLowerCase().match(rx); L= a.length; while(i{amp}lt;L){ if(!b[i]) return 1; a1= a[i], b1= b[i  ]; if(a1!== b1){ n= a1-b1; if(!isNaN(n)) return n; return a1{amp}gt;b1? 1:-1; } } return b[i]? -1:0; } 

Pero para acelerar la clasificación de una matriz, manipule la matriz antes de ordenarla, de modo que solo tenga que hacer conversiones en minúsculas y la expresión regular una vez en lugar de en cada paso de la clasificación.

 function naturalSort(ar, index){ var L= ar.length, i, who, next, isi= typeof index== 'number', rx= /(.d )|(d (.d )?)|([^d.] )|(.(D |$))/g; function nSort(aa, bb){ var a= aa[0], b= bb[0], a1, b1, i= 0, n, L= a.length; while(i{amp}lt;L){ if(!b[i]) return 1; a1= a[i]; b1= b[i  ]; if(a1!== b1){ n= a1-b1; if(!isNaN(n)) return n; return a1{amp}gt;b1? 1: -1; } } return b[i]!= undefined? -1: 0; } for(i= 0; i{amp}lt;L; i  ){ who= ar[i]; next= isi? ar[i][index] || '': who; ar[i]= [String(next).toLowerCase().match(rx), who]; } ar.sort(nSort); for(i= 0; i{amp}lt;L; i  ){ ar[i]= ar[i][1]; } } 

La biblioteca más completa para manejar esto a partir de 2019 parece ser de orden natural .

 const { orderBy } = require('natural-orderby') const unordered = [ '123asd', '19asd', '12345asd', 'asd123', 'asd12' ] const ordered = orderBy(unordered) // [ '19asd', // '123asd', // '12345asd', // 'asd12', // 'asd123' ] 

No solo toma matrices de cadenas, sino que también puede ordenar por el valor de una determinada clave en una matriz de objetos. También puede identificar y ordenar automáticamente cadenas de: monedas, fechas, moneda y muchas otras cosas.

Sorprendentemente, también es solo 1.6kB cuando se comprime.

Si tiene una variedad de objetos, puede hacer esto:

 var myArrayObjects = [{ "id": 1, "name": "1 example" }, { "id": 2, "name": "100 example" }, { "id": 3, "name": "12 example" }, { "id": 4, "name": "5 example" }, ] myArrayObjects = myArrayObjects.sort(function(a, b) { return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' }); }); console.log(myArrayObjects); 

Imagine una función de relleno de 8 dígitos que transforma:

  • ‘123asd’ -{amp}gt; ‘00000123asd’
  • ’19asd’ -{amp}gt; ‘00000019asd’

Podemos usar las cadenas acolchadas para ayudarnos a clasificar ’19asd’ para que aparezca antes de ‘123asd’.

Use la expresión regular /d /g para ayudar a encontrar todos los números que deben rellenarse:

 str.replace(/d /g, pad) 

A continuación se muestra la clasificación mediante esta técnica:

 var list = [ '123asd', '19asd', '12345asd', 'asd123', 'asd12' ]; function pad(n) { return ("00000000"   n).substr(-8); } function natural_expand(a) { return a.replace(/d /g, pad) }; function natural_compare(a, b) { return natural_expand(a).localeCompare(natural_expand(b)); } console.log(list.map(natural_expand).sort()); // intermediate values console.log(list.sort(natural_compare)); // result 

Los resultados intermedios muestran lo que hace la rutina natural_expand () y le da una idea de cómo funcionará la rutina natural_compare posterior:

 [ "00000019asd", "00000123asd", "00012345asd", "asd00000012", "asd00000123" ] 

Salidas:

 [ "19asd", "123asd", "12345asd", "asd12", "asd123" ] 

Sobre la base de la respuesta de @Adrien Be anterior y utilizando el código que crearon Brian Huisman y David Koelle , aquí hay un prototipo modificado para una variedad de objetos:

 //Usage: unsortedArrayOfObjects.alphaNumObjectSort("name"); //Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}]; //Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}] // **Sorts in place** Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) { for (var z = 0, t; t = this[z]; z  ) { this[z].sortArray = new Array(); var x = 0, y = -1, n = 0, i, j; while (i = (j = t[attribute].charAt(x  )).charCodeAt(0)) { var m = (i == 46 || (i {amp}gt;=48 {amp}amp;{amp}amp; i {amp}lt;= 57)); if (m !== n) { this[z].sortArray[  y] = ""; n = m; } this[z].sortArray[y]  = j; } } this.sort(function(a, b) { for (var x = 0, aa, bb; (aa = a.sortArray[x]) {amp}amp;{amp}amp; (bb = b.sortArray[x]); x  ) { if (caseInsensitive) { aa = aa.toLowerCase(); bb = bb.toLowerCase(); } if (aa !== bb) { var c = Number(aa), d = Number(bb); if (c == aa {amp}amp;{amp}amp; d == bb) { return c - d; } else { return (aa {amp}gt; bb) ? 1 : -1; } } } return a.sortArray.length - b.sortArray.length; }); for (var z = 0; z {amp}lt; this.length; z  ) { // Here we're deleting the unused "sortArray" instead of joining the string parts delete this[z]["sortArray"]; } }