Как отсортировать двухмерный массив по значению столбца?


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, все те, кто в настоящее время получил наибольшее количество голосов, ошибаются!
Bergi

@jahroy: Дело не в приведении типов, а в требованиях к последовательным функциям сравнения.
Bergi

Ответы:


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 . Прямо из опубликованной вами ссылки на документацию: «Если compareFunction не указан, элементы сортируются путем преобразования их в строки и сравнения строк в лексикографическом (« словарь »или« телефонная книга », а не в числовом) порядке. Например, появляется« 80 » перед «9» в лексикографическом порядке, но в числовой сортировке 9 идет перед 80 ».
Ян

3
@ Ян - Ты прав. Хорошая точка зрения. Думаю, я был слишком взволнован, чтобы доказать свою точку зрения о простоте. Я проверил это, но не полностью. Сейчас я исправлю это ... Хотелось бы, чтобы образцы данных подтвердили вашу точку зрения, прежде чем я размазал это яйцо по всему лицу!
jahroy

Ха-ха, я знаю, я знаю, я ненавижу, когда такое случается. Это выглядит так хорошо, но что-то внутренне меняет его, что не соответствует ожиданиям. Что-то вроде сравнения строк с помощью <или >. В любом случае, мне нравится обновление :)
Ян

1
@Ash - Лучшее место для поиска - это документация. Мне нравится документация Mozilla, поэтому, когда у меня возникает вопрос о функции JS, я всегда ищу в Google "mdn {{function_name}}". В этом случае поисковым запросом будет "mdn array.sort", что приведет вас сюда .
jahroy 07

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

Это правильный ответ, он учитывает обе цифры в номере. Благодарность!
Ник

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 голосов за явно неправильное решение? Я не могу в это поверить. Прочтите о функциях сравнения и поймите, когда они должны возвращать отрицательные значения.
Bergi

6
Как заявил Берги, это неправильное решение. Хотя это может сработать во многих случаях, будут моменты, когда это не сработает так, как ожидалось, и вы останетесь чесать голову (это случилось со мной). Суть проблемы в том, что функция сравнения в этом решении возвращает только два состояния (истина / 1, ложь / 0), но она должна возвращать три состояния (ноль, больше нуля и меньше нуля).
thdoan

1
У меня не получилось. @jahroy - человек с правильным ответом
erdomester

Просто примечание для тех, кто читает комментарии: ответ был исправлен 5 января. Теперь он правильный (функция сравнения возвращает три возможных состояния).
marlar

@Bergi, спасибо, что указали на это. (для меня это не работает должным образом в IE11), и я не мог понять (почему он работает в Chrome), пока не увидел ваш комментарий. Благодарность!
Alex Nevsky

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 07
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.