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


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

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

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.


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)


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

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

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

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.


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

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"],
                          ]"
*/

}

Update von möglichem Interesse - 2. Juli 2019. Sortierung ist jetzt 'stabil'. Lies hier. (über Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.