¿Cómo ordenar una matriz bidimensional por valor de columna?

90

¿Alguien puede ayudarme a ordenar una matriz bidimensional en JavaScript?

Tendrá datos en el siguiente formato:

[12, AAA]
[58, BBB]
[28, CCC]
[18, DDD]

Debería verse así cuando se ordena:

[12, AAA]
[18, DDD]
[28, CCC]
[58, BBB]

Básicamente, ordenando por la primera columna.

Salud

Alex
fuente
3
Aquí está todo lo que necesita saber: MDN - Array.sort ()
jahroy
1
por favor acepte la respuesta de @PramodVemulapalli, ¡todos los que actualmente han recibido una alta votación están equivocados!
Bergi
@jahroy: No se trata de la coerción de tipo, se trata de los requisitos para funciones de comparación coherentes.
Bergi

Respuestas:

110

Es así de simple:

var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']];

a.sort(sortFunction);

function sortFunction(a, b) {
    if (a[0] === b[0]) {
        return 0;
    }
    else {
        return (a[0] < b[0]) ? -1 : 1;
    }
}

Los invito a leer la documentación .

Si desea ordenar por la segunda columna, puede hacer esto:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}
jahroy
fuente
4
Realmente pruebe su código. jsfiddle.net/DuR4B/2 . Directamente desde el enlace de documentación que publicó: "Si no se proporciona compareFunction, los elementos se ordenan convirtiéndolos en cadenas y comparando cadenas en orden lexicográfico (" diccionario "o" directorio telefónico ", no numérico). Por ejemplo," 80 "viene antes de "9" en orden lexicográfico, pero en orden numérico, 9 viene antes de 80. "
Ian
3
@Ian - Tienes razón. Buen punto. Supongo que me emocioné demasiado para demostrar un punto sobre la simplicidad. Lo probé, pero no del todo. Ahora lo arreglaré ... ¡Ojalá los datos de muestra hubieran demostrado tu punto antes de que me untara la cara con ese huevo!
jahroy
Jaja, lo sé, lo sé, odio cuando suceden ese tipo de cosas. Se ve muy bien, pero algo lo cambia internamente y no funciona como se esperaba. Es como comparar cadenas con <o >. De todos modos, me gusta la actualización :)
Ian
1
@Ash: el mejor lugar para buscar es la documentación. Me gusta la documentación de Mozilla, así que cuando tengo una pregunta sobre una función JS, siempre busco en Google "mdn {{function_name}} " . En este caso, el término de búsqueda sería "mdn array.sort", lo que te trae aquí .
jahroy
1
... como verá en la documentación, el método array.sort () toma una función como argumento, lo cual es bastante común en JavaScript. El método array.sort () está diseñado de manera que sepa qué hacer con la función que se le pasa: lo usa para comparar sus elementos. Aquí hay un violín realmente tonto que hice para tratar de demostrar cómo se pasan funciones como referencias ... lo siento, es tan malo.
jahroy
65

El mejor enfoque sería utilizar lo siguiente, ya que puede haber valores repetitivos en la primera columna.

var arr = [[12, 'AAA'], [12, 'BBB'], [12, 'CCC'],[28, 'DDD'], [18, 'CCC'],[12, 'DDD'],[18, 'CCC'],[28, 'DDD'],[28, 'DDD'],[58, 'BBB'],[68, 'BBB'],[78, 'BBB']];

arr.sort(function(a,b) {
    return a[0]-b[0]
});
Pramod Vemulapalli
fuente
Esta es la respuesta correcta, toma en consideración ambos dígitos del número. ¡Gracias!
nick
52

prueba esto

//WITH FIRST COLUMN
arr = arr.sort(function(a,b) {
    return a[0] - b[0];
});


//WITH SECOND COLUMN
arr = arr.sort(function(a,b) {
    return a[1] - b[1];
});

Nota: La respuesta original usó mayor que (>) en lugar de menos (-), que es a lo que los comentarios se refieren como incorrectos.

PSR
fuente
8
¿8 votos a favor por una solución descaradamente incorrecta? No puedo creer esto. Por favor, lea acerca de las funciones de comparación y comprenda cuándo deben devolver valores negativos.
Bergi
6
Como dijo Bergi, esta no es la solución correcta. Si bien puede funcionar en muchos casos, habrá ocasiones en las que no funcionará como se esperaba y te dejarás rascándote la cabeza (me ha pasado a mí). El meollo del problema es que la función de comparación en esta solución solo devuelve dos estados (verdadero / 1, falso / 0), pero debería devolver tres estados (cero, mayor que cero y menor que cero).
jueves
1
No funcionó para mí. @jahroy es el hombre con la respuesta correcta
erdomester
Solo una nota para los que lean los comentarios: la respuesta se corrigió el 5 de enero. Ahora es correcta (la función de comparación devuelve tres estados posibles).
marlar
@Bergi, gracias por señalar esto. (para mí, no funciona correctamente en IE11) y no pude entender (por qué funciona en Chrome) hasta que vi su comentario. ¡Gracias!
Alex Nevsky
12

Usando la función de flecha y ordenando por el segundo campo de cadena

var a = [[12, 'CCC'], [58, 'AAA'], [57, 'DDD'], [28, 'CCC'],[18, 'BBB']];
a.sort((a, b) => a[1].localeCompare(b[1]));
console.log(a)

Dinesh Rajan
fuente
10

Si eres como yo, no querrás cambiar cada índice cada vez que quieras cambiar la columna por la que estás ordenando.

function sortByColumn(a, colIndex){

    a.sort(sortFunction);

    function sortFunction(a, b) {
        if (a[colIndex] === b[colIndex]) {
            return 0;
        }
        else {
            return (a[colIndex] < b[colIndex]) ? -1 : 1;
        }
    }

    return a;
}

var sorted_a = sortByColumn(a, 2);
Charles Clayton
fuente
Acabo de ver su respuesta, después de redactar una respuesta yo mismo con exactamente el mismo razonamiento, con una pequeña diferencia, de hecho devuelvo la función para ordenar directamente.
olamotte
3

Nada especial, solo se ahorra el costo que se necesita para devolver un valor en cierto índice de una matriz.

function sortByCol(arr, colIndex){
    arr.sort(sortFunction)
    function sortFunction(a, b) {
        a = a[colIndex]
        b = b[colIndex]
        return (a === b) ? 0 : (a < b) ? -1 : 1
    }
}
// Usage
var a = [[12, 'AAA'], [58, 'BBB'], [28, 'CCC'],[18, 'DDD']]
sortByCol(a, 0)
console.log(JSON.stringify(a))
// "[[12,"AAA"],[18,"DDD"],[28,"CCC"],[58,"BBB"]]"
Vikas Gautam
fuente
¿En qué se diferencia esta respuesta de la mía aquí ?
Charles Clayton
1
1. está usando a[colIndex]una y otra vez, pero lo estoy captando aquí a = a[colIndex]. Es más eficiente. 2. Estoy usando un sabor diferente de if, haciéndolo más corto. 3. No regreso arrcomo resultado de la sortByColfunción, lo que significa que mi función no se puede usar para crear otra referencia. ¡Espero eso ayude!
Vikas Gautam
3

en una línea:

var cars = [
  {type:"Volvo", year:2016},
  {type:"Saab", year:2001},
  {type:"BMW", year:2010}
]


function myFunction() {
  return cars.sort((a, b)=> a.year - b.year)
}
Jared
fuente
3

Si desea ordenar según la primera columna (que contiene el valor numérico ), intente esto:

arr.sort(function(a,b){
  return a[0]-b[0]
})

Si desea ordenar según la segunda columna (que contiene un valor de cadena ), intente esto:

arr.sort(function(a,b){
  return a[1].charCodeAt(0)-b[1].charCodeAt(0)
})

PD para el segundo caso, debe comparar entre sus valores ASCII.

Espero que esto ayude.

Sabbir Ahmed
fuente
0

Como mi caso de uso involucra docenas de columnas, expandí un poco la respuesta de @jahroy. (también me acabo de dar cuenta de que @ charles-clayton tenía la misma idea).
Paso el parámetro por el que quiero ordenar, y la función de ordenación se redefine con el índice deseado para que se lleve a cabo la comparación.

var ID_COLUMN=0
var URL_COLUMN=1

findings.sort(compareByColumnIndex(URL_COLUMN))

function compareByColumnIndex(index) {
  return function(a,b){
    if (a[index] === b[index]) {
        return 0;
    }
    else {
        return (a[index] < b[index]) ? -1 : 1;
    }
  }
}
Olamotte
fuente
0

De pie sobre los hombros de charles-clayton y @ vikas-gautam, agregué la prueba de cuerdas que se necesita si una columna tiene cuerdas como en OP.

return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;

La prueba isNaN(a-b)determina si las cadenas no se pueden convertir en números. Si pueden, la a-bprueba es válida.

Tenga en cuenta que ordenar una columna de tipos mixtos siempre dará un resultado entretenido ya que la prueba de igualdad estricta (a === b)siempre devolverá falso. Ver MDN aquí

Este es el script completo con la prueba de Logger, usando Google Apps Script.

function testSort(){

function sortByCol(arr, colIndex){
    arr.sort(sortFunction);
    function sortFunction(a, b) {
        a = a[colIndex];
        b = b[colIndex];
       return isNaN(a-b) ? (a === b) ? 0 : (a < b) ? -1 : 1 : a-b  ;  // test if text string - ie cannot be coerced to numbers.
       // Note that sorting a column of mixed types will always give an entertaining result as the strict equality test will always return false
       // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness

       }
}
// Usage
var a = [ [12,'12', 'AAA'],
          [12,'11', 'AAB'],
          [58,'120', 'CCC'],
          [28,'08', 'BBB'],
          [18,'80', 'DDD'],
        ]
    var arr1 = a.map(function (i){return i;}).sort();  // use map to ensure tests are not corrupted by a sort in-place.

    Logger.log("Original unsorted:\n     " + JSON.stringify(a));
    Logger.log("Vanilla sort:\n     " + JSON.stringify(arr1));
    sortByCol(a, 0);
    Logger.log("By col 0:\n     " + JSON.stringify(a));
    sortByCol(a, 1);
    Logger.log("By col 1:\n     " + JSON.stringify(a));
    sortByCol(a, 2);
    Logger.log("By col 2:\n     " + JSON.stringify(a));

/* vanilla sort returns " [
                            [12,"11","AAB"],
                            [12,"12","AAA"],
                            [18,"80","DDD"],
                            [28,"08","BBB"],
                            [58,"120","CCC"]
                          ]
   if col 0 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [18,'80',"DDD"],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"]
                          ]"
   if col 1 then returns "[
                            [28,'08',"BBB"],
                            [12,'11', 'AAB'],
                            [12,'12',"AAA"],
                            [18,'80',"DDD"],
                            [58,'120',"CCC"],

                          ]"
   if col 2 then returns "[
                            [12,'12',"AAA"],
                            [12,'11', 'AAB'],
                            [28,'08',"BBB"],
                            [58,'120',"CCC"],
                            [18,'80',"DDD"],
                          ]"
*/

}
DeeKay789
fuente
Actualización de posible interés - 2 de julio de 2019. Sort es ahora 'estable'. Leer aquí. (a través de Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789