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


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

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

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.


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)


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

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

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

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.


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

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

}

Aktualizacja możliwego zainteresowania - 2 lipca 2019 r. Sortowanie jest teraz „stabilne”. Przeczytaj tutaj. (via Mathias BynensVerified @mathias) v8.dev/features/stable-sort
— DeeKay789,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.