Jak posortować dwuwymiarową tablicę według wartości kolumny?

90

Czy ktoś może mi pomóc w sortowaniu dwuwymiarowej tablicy w JavaScript?

Będzie zawierał dane w następującym formacie:

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

Po posortowaniu powinno wyglądać tak:

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

Zasadniczo sortowanie według pierwszej kolumny.

Twoje zdrowie

Alex
źródło
3
Oto wszystko, co musisz wiedzieć: MDN - Array.sort ()
jahroy
1
proszę przyjąć odpowiedź @PramodVemulapalli, wszyscy ci, którzy obecnie wysoko ocenili, są w błędzie!
Bergi
@jahroy: Nie chodzi o wymuszenie typu, chodzi o wymagania dotyczące spójnych funkcji porównawczych.
Bergi

Odpowiedzi:

110

To takie proste:

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

Zapraszam do zapoznania się z dokumentacją .

Jeśli chcesz posortować według drugiej kolumny, możesz to zrobić:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}
jahroy
źródło
4
Przetestuj swój kod. jsfiddle.net/DuR4B/2 . Prosto z linku do dokumentacji, który opublikowałeś: „Jeśli nie podano funkcji compareFunction, elementy są sortowane, przekształcając je w łańcuchy i porównując ciągi w porządku leksykograficznym („ słownikowym ”lub„ książkowym ”, a nie numerycznym). przed „9” w porządku leksykograficznym, ale w przypadku numerycznym 9 występuje przed 80. ”
Ian
3
@Ian - Masz rację. Słuszna uwaga. Wydaje mi się, że byłem zbyt podekscytowany, aby udowodnić swoją prostotę. Przetestowałem to, ale nie do końca. Teraz to naprawię ... Chciałbym, żeby dane z próbek potwierdziły twój punkt widzenia, zanim rozsmarowałem to jajko na całej twarzy!
jahroy
Haha, wiem, wiem, nienawidzę, kiedy coś takiego się dzieje. Wygląda tak dobrze, ale coś wewnętrznie go zmienia, co nie działa zgodnie z oczekiwaniami. Coś jak porównywanie ciągów znaków z <lub >. W każdym razie podoba mi się aktualizacja :)
Ian
1
@Ash - Najlepszym miejscem do obejrzenia jest dokumentacja. Podoba mi się dokumentacja Mozilli, więc kiedy mam pytanie dotyczące funkcji JS, zawsze wpisuję w wyszukiwarkę „mdn {{nazwa_funkcji}}. W tym przypadku wyszukiwanym hasłem będzie „mdn array.sort”, co prowadzi do tego miejsca .
jahroy
1
... jak zobaczysz w dokumentacji, metoda array.sort () przyjmuje funkcję jako argument, co jest dość powszechne w JavaScript. Metoda array.sort () została zaprojektowana w taki sposób, aby wiedziała, co zrobić z przekazaną do niej funkcją: używa jej do porównania swoich elementów. Oto naprawdę kiepskie skrzypce, które zrobiłem, aby pokazać, jak przekazujesz funkcje jako referencje ... przepraszam, że jest tak źle.
jahroy
65

Najlepszym podejściem byłoby użycie następujących, ponieważ w pierwszej kolumnie mogą występować powtarzające się wartości.

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
źródło
To jest poprawna odpowiedź, bierze pod uwagę obie cyfry w numerze. Dzięki!
nick
52

Spróbuj tego

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

Uwaga: Oryginalna odpowiedź zawierała większe niż (>) zamiast minus (-), co jest określane w komentarzach jako niepoprawne.

PSR
źródło
8
8 głosów poparcia za rażąco złe rozwiązanie? Nie mogę w to uwierzyć. Przeczytaj o funkcjach porównawczych i zrozum, kiedy muszą zwracać wartości ujemne.
Bergi
6
Jak stwierdził Bergi, nie jest to właściwe rozwiązanie. Chociaż może to działać w wielu przypadkach, będą chwile, w których nie będzie działać zgodnie z oczekiwaniami i będziesz drapać się po głowie (to mi się przydarzyło). Sedno problemu polega na tym, że funkcja porównania w tym rozwiązaniu zwraca tylko dwa stany (prawda / 1, fałsz / 0), ale powinna zwracać trzy stany (zero, większe od zera i mniejsze od zera).
15.15
1
Nie działa dla mnie. @jahroy to człowiek z poprawną odpowiedzią
erdomester
Tylko uwaga dla czytających komentarze: Odpowiedź została poprawiona 5 stycznia. Teraz jest poprawna (funkcja porównania zwraca trzy możliwe stany).
marlar
@Bergi, dziękuję za wskazanie tego. (dla mnie nie działa poprawnie w IE11) i nie byłem w stanie zrozumieć (dlaczego działa w chrome), dopóki nie zobaczyłem twojego komentarza. Dzięki!
Alex Nevsky,
12

Korzystanie z funkcji strzałek i sortowanie według drugiego pola ciągu

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
źródło
10

Jeśli jesteś podobny do mnie, nie będziesz chciał przechodzić przez zmianę każdego indeksu za każdym razem, gdy chcesz zmienić kolumnę, według której sortujesz.

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
źródło
Właśnie zobaczyłem twoją odpowiedź, po tym jak sam przygotowałem odpowiedź z dokładnie tym samym rozumowaniem - z małą różnicą - w rzeczywistości zwracam funkcję do bezpośredniego sortowania.
olamotte
3

Nic specjalnego, po prostu oszczędzamy koszt potrzebny do zwrócenia wartości o określonym indeksie z tablicy.

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
źródło
Czym ta odpowiedź różni się od mojej tutaj ?
Charles Clayton
1
1. używasz a[colIndex]wielokrotnie, ale łapię to tutaj a = a[colIndex]. Jest bardziej wydajna. 2. Używam innego smaku if, przez co jest krótszy. 3. Nie zwracam arrwyniku w wyniku działania sortByColfunkcji, co oznacza, że ​​nie można użyć mojej funkcji do utworzenia innego odwołania. Mam nadzieję, że to pomoże!
Vikas Gautam
3

w jednej linii:

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
źródło
3

Jeśli chcesz posortować według pierwszej kolumny (która zawiera numer wartość), a następnie spróbuj tego:

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

Jeśli chcesz sortować na podstawie drugiej kolumny (która zawiera ciąg wartość ), spróbuj tego:

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

PS w drugim przypadku musisz porównać ich wartości ASCII.

Mam nadzieję że to pomoże.

Sabbir Ahmed
źródło
0

Ponieważ mój przypadek użycia obejmuje dziesiątki kolumn, rozszerzyłem nieco odpowiedź @ jahroy. (właśnie zdałem sobie sprawę, że @ charles-clayton miał ten sam pomysł).
Przekazuję parametr, według którego chcę sortować, a funkcja sortowania jest ponownie definiowana z żądanym indeksem, aby miało miejsce porównanie.

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
źródło
0

Stojąc na ramionach Charlesa-Claytona i @ vikas-gautam, dodałem test strun, który jest potrzebny, jeśli kolumna ma struny jak w OP.

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

Test isNaN(a-b)określa, czy ciągów nie można przekształcić w liczby. Jeśli tak, a-btest jest ważny.

Zwróć uwagę, że sortowanie kolumny typów mieszanych zawsze da zabawny wynik, ponieważ test ścisłej równości (a === b)zawsze zwróci fałsz. Zobacz MDN tutaj

To jest pełny skrypt z testem Loggera - przy użyciu 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
źródło
Aktualizacja możliwego zainteresowania - 2 lipca 2019 r. Sortowanie jest teraz „stabilne”. Przeczytaj tutaj. (via Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789,