Wie sortiere ich ein zweidimensionales Array nach einem Spaltenwert?

89

Kann mir jemand helfen, ein zweidimensionales Array in JavaScript zu sortieren?

Es werden Daten im folgenden Format vorliegen:

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

Beim Sortieren sollte es so aussehen:

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

Also im Grunde nach der ersten Spalte sortieren.

Prost

Alex
quelle
3
Hier ist alles, was Sie wissen müssen: MDN - Array.sort ()
jahroy
1
Bitte akzeptieren Sie die Antwort von @PramodVemulapalli, alle diejenigen, die derzeit hoch gewählt sind, sind falsch!
Bergi
@jahroy: Es geht nicht um den Typenzwang, sondern um die Anforderungen an konsistente Vergleichsfunktionen.
Bergi

Antworten:

110

So einfach ist das:

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

Ich lade Sie ein, die Dokumentation zu lesen .

Wenn Sie nach der zweiten Spalte sortieren möchten, können Sie dies tun:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}
jahroy
quelle
4
Bitte testen Sie Ihren Code tatsächlich. jsfiddle.net/DuR4B/2 . Direkt aus dem von Ihnen geposteten Dokumentationslink: "Wenn compareFunction nicht angegeben ist, werden Elemente sortiert, indem sie in Zeichenfolgen konvertiert und Zeichenfolgen in lexikografischer Reihenfolge (" Wörterbuch "oder" Telefonbuch ", nicht numerisch) verglichen werden. Beispielsweise wird" 80 "angezeigt vor "9" in lexikographischer Reihenfolge, aber in einer numerischen Sortierung steht 9 vor 80. "
Ian
3
@ Ian - Du hast recht. Guter Punkt. Ich glaube, ich war übermäßig aufgeregt, einen Punkt über Einfachheit zu beweisen. Ich habe es getestet, aber nicht vollständig. Jetzt werde ich es reparieren ... Ich wünschte, die Probendaten hätten Ihren Standpunkt bewiesen, bevor ich mir das Ei ins Gesicht geschmiert habe!
Jahroy
Haha, ich weiß, ich weiß, ich hasse es, wenn so etwas passiert. Es sieht so richtig aus, aber etwas ändert es intern, das nicht wie erwartet funktioniert. Ein bisschen wie das Vergleichen von Strings mit <oder >. Wie auch immer, ich mag das Update :)
Ian
1
@Ash - Der beste Ort, um nachzuschauen, ist die Dokumentation. Ich mag die Dokumentation von Mozilla. Wenn ich also eine Frage zu einer JS-Funktion habe, gehe ich immer auf "mdn {{Funktionsname}} ". In diesem Fall wäre der Suchbegriff "mdn array.sort", was Sie hierher bringt .
Jahroy
1
... wie Sie in der Dokumentation sehen werden, verwendet die Methode array.sort () eine Funktion als Argument, was in JavaScript ziemlich häufig vorkommt. Die array.sort () -Methode ist so konzipiert, dass sie weiß, was mit der an sie übergebenen Funktion zu tun ist: Sie verwendet sie zum Vergleichen ihrer Elemente. Hier ist eine wirklich lahme Geige, die ich gemacht habe, um zu demonstrieren, wie Sie Funktionen als Referenzen übergeben ... Entschuldigung, es ist so schlimm.
Jahroy
65

Der beste Ansatz wäre, Folgendes zu verwenden, da sich in der ersten Spalte möglicherweise sich wiederholende Werte befinden.

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
quelle
Dies ist die richtige Antwort, sie berücksichtigt beide Ziffern in der Nummer. Vielen Dank!
Nick
52

Versuche dies

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

Hinweis: Bei der ursprünglichen Antwort wurde ein Größer als (>) anstelle von Minus (-) verwendet, was in den Kommentaren als falsch bezeichnet wird.

PSR
quelle
8
8 Gegenstimmen für eine offensichtlich falsche Lösung? Ich kann das nicht glauben. Bitte lesen Sie die Vergleichsfunktionen und verstehen Sie, wann sie negative Werte zurückgeben müssen.
Bergi
6
Wie Bergi sagte, ist dies nicht die richtige Lösung. Obwohl es in vielen Fällen funktionieren kann, wird es Zeiten geben, in denen es nicht wie erwartet funktioniert und Sie sich am Kopf kratzen (es ist mir passiert). Der Kern des Problems besteht darin, dass die Vergleichsfunktion in dieser Lösung nur zwei Zustände zurückgibt (wahr / 1, falsch / 0), aber drei Zustände zurückgeben sollte (null, größer als null und kleiner als null).
Donnerstag,
1
Hat bei mir nicht funktioniert. @ Jahroy ist der Mann mit der richtigen Antwort
Erdomester
Nur eine Anmerkung für diejenigen, die die Kommentare lesen: Die Antwort wurde am 5. Januar korrigiert. Sie ist jetzt korrekt (die Vergleichsfunktion gibt drei mögliche Zustände zurück).
Marlar
@Bergi, danke, dass du darauf hingewiesen hast. (Für mich funktioniert es in IE11 nicht richtig) und ich konnte nicht verstehen (warum es in Chrome funktioniert), bis ich Ihren Kommentar gesehen habe. Vielen Dank!
Alex Nevsky
12

Verwenden der Pfeilfunktion und Sortieren nach dem zweiten Zeichenfolgenfeld

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
quelle
10

Wenn Sie so etwas wie ich sind, möchten Sie nicht jedes Mal, wenn Sie die Spalte ändern möchten, nach der Sie sortieren, jeden Index ändern.

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
quelle
Ich habe gerade Ihre Antwort gesehen, nachdem ich selbst eine Antwort mit genau der gleichen Begründung verfasst habe - mit einem kleinen Unterschied -, gebe ich die Funktion tatsächlich zurück, um sie direkt zu sortieren.
Olamotte
3

Nichts Besonderes, nur die Kosten zu sparen, die erforderlich sind, um einen Wert für einen bestimmten Index aus einem Array zurückzugeben.

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
quelle
Wie unterscheidet sich diese Antwort von meiner hier ?
Charles Clayton
1
1. Sie verwenden a[colIndex]immer wieder, aber ich fange es hier a = a[colIndex]. Es ist effizienter. 2. Ich verwende verschiedene Geschmacksrichtungen von if, wodurch es kürzer wird. 3. Ich kehre arraufgrund einer sortByColFunktion nicht zurück, was bedeutet, dass meine Funktion nicht zum Erstellen einer weiteren Referenz verwendet werden kann. Ich hoffe es hilft!
Vikas Gautam
3

in einer Zeile:

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
quelle
3

Wenn Sie nach der ersten Spalte sortieren möchten (die den Zahlenwert enthält ), versuchen Sie Folgendes:

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

Wenn Sie nach der zweiten Spalte sortieren möchten (die einen Zeichenfolgenwert enthält ), versuchen Sie Folgendes:

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

PS Für den zweiten Fall müssen Sie zwischen ihren ASCII-Werten vergleichen.

Hoffe das hilft.

Sabbir Ahmed
quelle
0

Da mein Anwendungsfall Dutzende von Spalten umfasst, habe ich die Antwort von @ jahroy ein wenig erweitert. (Ich habe auch gerade festgestellt, dass @ charles-Clayton die gleiche Idee hatte.)
Ich übergebe den Parameter, nach dem ich sortieren möchte, und die Sortierfunktion wird mit dem gewünschten Index neu definiert, damit der Vergleich stattfinden kann.

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
quelle
0

Ich stand auf den Schultern von Charles-Clayton und @ Vikas-Gautam und fügte den Stringtest hinzu, der erforderlich ist, wenn eine Spalte Strings wie in OP enthält.

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

Der Test stellt isNaN(a-b)fest, ob die Zeichenfolgen nicht zu Zahlen gezwungen werden können. Wenn sie können, ist der a-bTest gültig.

Beachten Sie, dass das Sortieren einer Spalte mit gemischten Typen immer ein unterhaltsames Ergebnis liefert, da der strenge Gleichheitstest (a === b)immer false zurückgibt. Siehe MDN hier

Dies ist das vollständige Skript mit Logger-Test - unter Verwendung von 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
quelle
Update von möglichem Interesse - 2. Juli 2019. Sortierung ist jetzt 'stabil'. Lies hier. (über Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789