Come ordinare la matrice bidimensionale in base al valore della colonna?


90

Qualcuno può aiutarmi a ordinare un array bidimensionale in JavaScript?

Avrà dati nel seguente formato:

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

Dovrebbe apparire così quando ordinato:

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

Quindi, in pratica, ordinamento per prima colonna.

Saluti


3
Ecco tutto ciò che devi sapere: MDN - Array.sort ()
jahroy

1
per favore accetta la risposta di @PramodVemulapalli, tutti quelli attualmente più votati si sbagliano!
Bergi

@jahroy: non si tratta della coercizione del tipo, ma dei requisiti per funzioni di confronto coerenti.
Bergi

Risposte:


113

È così semplice:

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;
    }
}

Vi invito a leggere la documentazione .

Se vuoi ordinare in base alla seconda colonna, puoi farlo:

a.sort(compareSecondColumn);

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

4
Per favore, prova effettivamente il tuo codice. jsfiddle.net/DuR4B/2 . Direttamente dal collegamento alla documentazione che hai pubblicato: "Se compareFunction non viene fornito, gli elementi vengono ordinati convertendoli in stringhe e confrontando le stringhe in ordine lessicografico (" dizionario "o" elenco telefonico ", non numerico). Ad esempio," 80 "viene prima di "9" in ordine lessicografico, ma in un ordinamento numerico 9 viene prima di 80 ".
Ian

3
@Ian - Hai ragione. Buon punto. Immagino di essermi eccitato all'idea di dimostrare un punto sulla semplicità. L'ho provato, ma non completamente. Ora lo aggiusterò ... Vorrei che i dati del campione avessero dimostrato il tuo punto prima di spalmarmi quell'uovo su tutta la faccia!
jahroy

Haha lo so lo so, odio quando succede questo genere di cose. Sembra così giusto, ma qualcosa internamente lo cambia che non funziona come previsto. Un po 'come confrontare le stringhe con <o >. Ad ogni modo, mi piace l'aggiornamento :)
Ian

1
@Ash - Il posto migliore dove guardare è la documentazione. Mi piace la documentazione di Mozilla, quindi quando ho una domanda su una funzione JS cerco sempre su Google "mdn {{function_name}} " . In questo caso il termine di ricerca sarebbe "mdn array.sort" che ti porta qui .
jahroy

1
... come vedrai nella documentazione, il metodo array.sort () accetta una funzione come argomento, cosa abbastanza comune in JavaScript. Il metodo array.sort () è progettato in modo da sapere cosa fare con la funzione che gli è stata passata: lo usa per confrontare i suoi elementi. Ecco un violino davvero debole che ho creato per provare a dimostrare come si passano le funzioni come riferimenti ... scusate, è così brutto.
jahroy

66

L'approccio migliore sarebbe utilizzare quanto segue, poiché potrebbero esserci valori ripetitivi nella prima colonna.

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]
});

Questa è la risposta corretta, prende in considerazione entrambe le cifre del numero. Grazie!
nick

53

prova questo

//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 risposta originale utilizzava un maggiore di (>) invece di meno (-) che è ciò a cui i commenti si riferiscono come errato.


8
8 voti positivi per una soluzione palesemente sbagliata? Non posso crederci. Per favore, leggi le funzioni di confronto e capisci quando devono restituire valori negativi.
Bergi

6
Come ha affermato Bergi, questa non è la soluzione giusta. Sebbene possa funzionare in molti casi, ci saranno momenti in cui non funzionerà come previsto e ti rimarrai a grattarti la testa (è successo a me). Il nocciolo del problema è che la funzione di confronto in questa soluzione restituisce solo due stati (vero / 1, falso / 0), ma dovrebbe restituire tre stati (zero, maggiore di zero e minore di zero).
giovedì

1
Non ha funzionato per me. @jahroy è l'uomo con la risposta corretta
erdomester

Solo una nota per coloro che leggono i commenti: la risposta è stata corretta il 5 gennaio. Ora è corretta (la funzione di confronto restituisce tre stati possibili).
marlar

@Bergi, grazie per averlo fatto notare. (per me, non funziona correttamente in IE11) e non sono stato in grado di capire (perché funziona in Chrome) finché non ho visto il tuo commento. Grazie!
Alex Nevsky

12

Utilizzo della funzione freccia e ordinamento in base al secondo campo stringa

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


10

Se sei come me, non vorrai cambiare ogni indice ogni volta che vuoi cambiare la colonna in base alla quale stai ordinando.

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);

Ho appena visto la tua risposta, dopo aver redatto io stesso una risposta con lo stesso identico ragionamento - con una piccola differenza - in realtà restituisco la funzione per ordinare direttamente.
olamotte

3

Niente di speciale, risparmiando solo il costo necessario per restituire un valore a un determinato indice da un array.

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"]]"

In che modo questa risposta è diversa dalla mia qui ?
Charles Clayton,

1
1. lo stai usando a[colIndex]ancora e ancora, ma lo prendo qui a = a[colIndex]. È più efficiente. 2. Sto usando un sapore diverso di if, rendendolo più corto. 3. Non sto restituendo arrcome risultato della sortByColfunzione, il che significa che la mia funzione non può essere utilizzata per creare un altro riferimento. Spero che sia d'aiuto!
Vikas Gautam

3

in una riga:

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)
}

3

Se vuoi ordinare in base alla prima colonna (che contiene il valore numerico ), prova questo:

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

Se vuoi ordinare in base alla seconda colonna (che contiene il valore della stringa ), prova questo:

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

PS per il secondo caso, è necessario confrontare i loro valori ASCII.

Spero che sia di aiuto.


0

Poiché il mio caso d'uso coinvolge dozzine di colonne, ho ampliato un po 'la risposta di @ jahroy. (
Ho anche appena realizzato che @ charles-clayton aveva la stessa idea.) Passo il parametro per cui desidero ordinare e la funzione di ordinamento viene ridefinita con l'indice desiderato per il confronto.

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;
    }
  }
}

0

In piedi sulle spalle di charles-clayton e @ vikas-gautam, ho aggiunto il test delle stringhe che è necessario se una colonna ha stringhe come in OP.

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

Il test isNaN(a-b)determina se le stringhe non possono essere convertite in numeri. Se possono, il filea-b test è valido.

Si noti che l'ordinamento di una colonna di tipi misti darà sempre un risultato divertente poiché il test di uguaglianza rigorosa (a === b)restituirà sempre false. Vedi MDN qui

Questo è lo script completo con il test Logger, utilizzando 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"],
                          ]"
*/

}

Aggiornamento di possibile interesse - 2 luglio 2019. L'ordinamento è ora 'stabile'. Leggi qui. (tramite Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.