Як відсортувати двовимірний масив за значенням стовпця?


90

Чи може хтось допомогти мені відсортувати двовимірний масив у JavaScript?

Він матиме дані у наступному форматі:

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

Це має виглядати так при сортуванні:

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

Отже, в основному сортування за першим стовпцем.

Ура


3
Ось усе, що вам потрібно знати: MDN - Array.sort ()
jahroy

1
будь ласка, прийміть відповідь @PramodVemulapalli, всі ті, хто в даний час має високі голоси, помиляються!
Бергі

@jahroy: Йдеться не про примус типу, а про вимоги до послідовних функцій порівняння.
Бергі

Відповіді:


110

Це все просто:

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

Запрошую ознайомитися з документацією .

Якщо ви хочете відсортувати за другим стовпцем, ви можете зробити це:

a.sort(compareSecondColumn);

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

4
Будь ласка, протестуйте свій код. jsfiddle.net/DuR4B/2 . Прямо з посилання на документацію, яке ви розмістили: "Якщо порівняння Функція не надається, елементи сортуються шляхом перетворення їх у рядки та порівняння рядків у лексикографічному (" словнику "або" телефонній книзі ", не числовому) порядку. Наприклад," 80 "приходить перед "9" у лексикографічному порядку, але в числовому сорті 9 поставляється перед 80. "
Ян

3
@Ian - Ти маєш рацію. Гарна думка. Я здогадуюсь, я надто збудився, щоб довести думку про простоту. Я тестував, але не повністю. Зараз я це виправлю ... Я хотів би, щоб зразкові дані довели вашу думку, перш ніж я розмазав це яйце по всьому обличчі!
jahroy

Ха-ха, я знаю, що знаю, я ненавиджу, коли таке трапляється. Це виглядає так правильно, але щось внутрішньо змінює це, що робить не так, як очікувалося. Подібно до порівняння рядків з <або >. У будь-якому випадку, мені подобається оновлення :)
Ян

1
@Ash - Найкраще шукати документацію. Мені подобається документація Mozilla, тому, коли у мене виникає запитання щодо функції JS, я завжди гуглюю "mdn {{function_name}} ". У цьому випадку пошуковим терміном буде "mdn array.sort", який приведе вас сюди .
jahroy

1
... як ви побачите в документації, метод array.sort () приймає функцію як аргумент, що досить часто зустрічається в JavaScript. Метод array.sort () розроблений таким чином, що він знає, що робити з переданою йому функцією: він використовує його для порівняння своїх елементів. Ось справді кульгава скрипка, яку я зробив, щоб спробувати продемонструвати, як ви передаєте функції як посилання ... вибачте, це так погано.
jahroy

65

Найкращим підходом було б використовувати наступне, оскільки в першому стовпці можуть бути повторювані значення.

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

Це правильна відповідь, вона враховує обидві цифри числа. Дякую!
nick

52

спробуйте це

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

Примітка: Оригінальна відповідь використовувала більше (>) замість мінус (-), що в коментарях називають неправильним.


8
8 голосів за очевидно неправильне рішення? Я не можу в це повірити. Будь ласка, прочитайте про функції порівняння та зрозумійте, коли їм потрібно повертати від’ємні значення.
Бергі

6
Як заявив Бергі, це не правильне рішення. Хоча це може працювати у багатьох випадках, бувають випадки, коли це не спрацьовує, як очікувалося, і ви залишаєтеся чухати голову (це траплялося зі мною). Суть проблеми полягає в тому, що функція порівняння у цьому рішенні повертає лише два стани (true / 1, false / 0), але вона повинна повертати три стани (нуль, більше нуля та менше нуля).
thdoan

1
Не працював у мене. @jahroy - людина з правильною відповіддю
erdomester

Лише примітка для тих, хто читає коментарі: відповідь була виправлена ​​5 січня. Зараз вона правильна (функція порівняння повертає три можливі стани).
марлар

@Bergi, дякую, що вказав на це. (для мене це працює неправильно в IE11), і я не зміг зрозуміти (чому це працює в chrome), поки не побачив ваш коментар. Дякую!
Олексій Невський,

12

Використання функції стрілки та сортування за другим рядковим полем

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

Якщо ви щось подібне до мене, вам не потрібно буде змінювати кожен індекс кожного разу, коли ви хочете змінити стовпець, за яким ви сортуєте.

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

Я щойно побачив вашу відповідь, після того, як сам склав відповідь із точно такими ж міркуваннями - з невеликою різницею - я фактично повертаю функцію безпосереднього сортування.
olamotte

3

Нічого особливого, лише економія витрат, необхідних для повернення значення з певним індексом із масиву.

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

Чим ця відповідь відрізняється від моєї тут ?
Чарльз Клейтон,

1
1. Ви використовуєте a[colIndex]знову і знову, але я ловлю це тут a = a[colIndex]. Це ефективніше. 2. Я використовую різний смак if, роблячи його коротшим. 3. Я не повертаюся arrв результаті sortByColфункції, що означає, що мою функцію не можна використовувати для створення іншого посилання. Сподіваюся, це допоможе!
Вікас Гаутам

3

в один рядок:

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

Якщо ви хочете відсортувати за першим стовпцем (який містить числове значення), спробуйте наступне:

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

Якщо ви хочете відсортувати на основі другого стовпця (який містить значення рядка ), спробуйте наступне:

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

PS для другого випадку вам потрібно порівняти їх значення ASCII.

Сподіваюся, це допомагає.


0

Оскільки мій сценарій використання включає десятки стовпців, я трохи розширив відповідь @ jahroy. (також щойно зрозумів, що @ charles-clayton мав ту ж ідею.)
Я передаю параметр, за яким я хочу відсортувати, і функція сортування перевизначається з необхідним індексом для порівняння.

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

Стоячи на плечах charles-clayton та @ vikas-gautam, я додав тестовий рядок, який потрібен, якщо стовпець має рядки, як в OP.

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

Тест isNaN(a-b)визначає, чи не можна прив'язувати рядки до чисел. Якщо вони можуть, тоді a-bтест є дійсним.

Зверніть увагу, що сортування стовпця змішаних типів завжди дасть цікавий результат, оскільки суворий тест на рівність (a === b)завжди повертає false. Дивіться MDN тут

Це повний сценарій з тестом Logger - за допомогою сценарію Google Apps.

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

}

Оновлення можливих відсотків - 2 липня 2019 р. Сортування тепер "стабільне". Читайте тут. (через Mathias BynensVerified @mathias) v8.dev/features/stable-sort
DeeKay789
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.