129

Can any one help me sort a 2 dimensional Array in JavaScript?

It will have data in the following format:

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

It should look like this when sorted:

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

So basically, sorting by the first column.

Cheers

3
  • 4
    Here's everything you need to know: MDN - Array.sort() Commented Apr 19, 2013 at 4:52
  • 1
    please accept the answer of @PramodVemulapalli, all those currently high-voted are wrong! Commented Jun 6, 2014 at 8:55
  • @jahroy: It's not about the type coercion, it's about the requirements for consistent comparison functions. Commented Jun 6, 2014 at 9:13

17 Answers 17

156

It's this simple:

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

I invite you to read the documentation.

If you want to sort by the second column, you can do this:

a.sort(compareSecondColumn);

function compareSecondColumn(a, b) {
    if (a[1] === b[1]) {
        return 0;
    }
    else {
        return (a[1] < b[1]) ? -1 : 1;
    }
}
Sign up to request clarification or add additional context in comments.

13 Comments

Please actually test your code. jsfiddle.net/DuR4B/2 . Straight from the documentation link you posted: "If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in lexicographic ("dictionary" or "telephone book," not numerical) order. For example, "80" comes before "9" in lexicographic order, but in a numeric sort 9 comes before 80."
@Ian - You're right. Good point. I guess I got over-excited to prove a point about simplicity. I did test it, but not completely. Now I'll fix it... I wish the sample data had proven your point before I smeared that egg all over my face!
Haha I know I know, I hate when that kind of thing happens. It looks so right but something internally changes it that doesn't do as expected. Kinda like comparing strings with < or >. Anyways, I like the update :)
@Ash - The best place to look is the documentation. I like Mozilla's documentation, so when I have a question about a JS function I always google "mdn {{function_name}}." In this case the search term would be "mdn array.sort" which brings you here.
... as you'll see in the documentation, the array.sort() method takes a function as an argument, which is fairly common in JavaScript. The array.sort() method is designed in a way that it knows what to do with the function passed to it: it uses it to compare its elements. Here's a really lame fiddle I made to try to demonstrate how you pass functions as references... sorry it's so bad.
|
84

The best approach would be to use the following, as there may be repetitive values in the first column.

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

1 Comment

This is correct answer, it takes into consideration both digits in the number . Thanks!
72

Try this:

//WITH FIRST COLUMN
arr = arr.sort((a, b) => a[0] - b[0]);

//WITH SECOND COLUMN
arr = arr.sort((a, b) => a[1] - b[1]);

Note: Original answer used a greater than (>) instead of minus (-) which is what the comments are referring to as incorrect.

6 Comments

8 upvotes for a blatantly wrong solution? I cannot believe this. Please, read about comparison functions and understand when they need to return negative values.
As Bergi stated, this is not the right solution. While it may work in many cases, there will be times where it won't work as expected and you're left scratching your head (it has happened to me). The crux of the problem is that the comparison function in this solution only returns two states (true/1, false/0), but it should be returning three states (zero, greater than zero, and less than zero).
Did not work for me. @jahroy is the man with the correct answer
Just a note for those reading the comments: The answer was corrected Jan 5. It is correct now (the compare function returns three possible states).
@Bergi, thank you for pointing this out. (for me, it doesn't work properly in IE11) and I was not able to understand (why it works in chrome) until I've seen your comment. Thanks!
|
18

Using the arrow function, and sorting by the second string field

var a = [[12, 'CCC'], [58, 'AAA'], [57, 'DDD'], [28, 'CCC'],[18, 'BBB']];
a.sort((a, b) => a[1].localeCompare(b[1]));
console.log(a)

1 Comment

This worked for me better with collator.compare
13

If you're anything like me, you won't want to go through changing each index every time you want to change the column you're sorting by.

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

1 Comment

I just saw your answer, after drafting an answer myself with the exact same reasoning - with a small difference - I actually return the function to sort directly.
8

in one line:

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

Comments

7

If you want to sort based on first column (which contains number value), then try this:

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

If you want to sort based on second column (which contains string value), then try this:

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

P.S. for the second case, you need to compare between their ASCII values.

Comments

3

Nothing special, just saving the cost it takes to return a value at certain index from an array.

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

2 Comments

How is this answer different from mine here?
1. you are using a[colIndex] again and again but I am catching it here a = a[colIndex]. It's more efficient. 2. I am using different flavor of if, making it more shorter. 3. I am not returning arr as a result of sortByCol function which means my function can't be use to create another reference. Hope it helps!
2

I use sort to sort the array

This is my code :

const sortArr = (arr) => {
    arr.sort((valA, valB) => valA[0] - valB[0])
    return arr
}

const arr = [
    [12, 'AAA'],
    [58, 'BBB'],
    [28, 'CCC'],
    [18, 'DDD']
]
console.log(sortArr(arr))

1 Comment

Thanks, this works. But note to others: this code is for number sorting only. For example on sorting by 3rd column see jsfiddle.net/oasjgvmc
1

Standing on the shoulders of charles-clayton and @vikas-gautam, I added the string test which is needed if a column has strings as in OP.

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

The test isNaN(a-b) determines if the strings cannot be coerced to numbers. If they can then the a-b test is valid.

Note that sorting a column of mixed types will always give an entertaining result as the strict equality test (a === b) will always return false. See MDN here

This is the full script with Logger test - using 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"],
                          ]"
*/

}

1 Comment

Update of possible interest - 2nd July, 2019. Sort is now 'stable'. Read here. (via Mathias BynensVerified @mathias) v8.dev/features/stable-sort
1
Solution vary depend on column value is numeric or string. 

To sort by first column if value is numeric,
array.sort( (a, b) => a[0] - b[0]);

To sort by second column if value is numeric,
array.sort( (a, b) => a[1] - b[1]);

To sort by first column if value is string/letter,
array.sort( function(a, b) {
    const nameA = a[0].toUpperCase(); // to avoid case while sort
    const nameB = b[0].toUpperCase();
    if(nameA > nameB)
        return 1;
    else if(nameB > nameA)
        return -1;
    else
        return 0;     
})

Comments

0

As my usecase involves dozens of columns, I expanded @jahroy's answer a bit. (also just realized @charles-clayton had the same idea.)
I pass the parameter I want to sort by, and the sort function is redefined with the desired index for the comparison to take place on.

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

Comments

0

Good idea Sabbir Ahmed, but only order by the first character, for three:

array.sort((a, b) => (a[n].charCodeAt(0)*1000000 + a[n].charCodeAt(1)*1000 + a[n].charCodeAt(2)) - (b[n].charCodeAt(0)*1000000 + b[n].charCodeAt(1)*1000 + b[n].charCodeAt(2)));

Comments

0

Sorting two dimensional array specifying the sort order and column. Default order 0 means no change hence order must be specified: 1 => Ascending, -1 => descending. Default column is 0.

let sort2d = (arr2d = [], order = 0, column = 0) => {
    if (column < 0 || column > 1) {
        if (order == 1) 
            return arr2d.sort((a, b) => a[column] - b[column])
        if (order == -1) 
            return arr2d.sort((a, b) => b[column] - a[column])
    }
    return arr2d
}

let arr2d = [ [5, 3], [2, 5], [9, 1], [4, 1] ]
console.log(sort2d(arr2d, 1, -1)) //  [ [ 2, 5 ], [ 5, 3 ], [ 9, 1 ], [ 4, 1 ] ]

Comments

0

If you want a solution to sort multi-dimensional integer array where sub-array have a fixed length [ [ -6, 1, 5 ], [ -8, 3, 5 ], [ -8, 2, 6 ], [ -8, 3, 6 ] ]

const array = [ [ -6, 1, 5 ], [ -8, 3, 5 ], [ -8, 2, 6 ], [ -8, 3, 6 ] ]
const multiArraySort = (array, num) => {
  return array = array.sort((a,b) => {
    let boolean = true
    let i = 0 
    while(boolean){      
      if(a[i] === b[i]){        
        if(a[i+1] === b[i+1]){          
          i < num - 1 ? i++ : boolean = false
        }else {          
          return a[i+1] - b[i+1]          
        }        
      } else {                
        return a[i] - b[i]
      }
    }
    return 0
  })
}
// 3 represents the fixed length of sub-array
let sarray = multiArraySort(array, 3) //cant' assign in const array

Answer: [ [ -8, 2, 6 ], [ -8, 3, 5 ], [ -8, 3, 6 ], [ -6, 1, 5 ] ]

Comments

0

The toSorted() method allows us to sort an array. Returns a new array with the ordered elements and does not modify the original. Just like the classic sort() method, we can pass it a comparison function to sort the elements.

Array.prototype.toSorted()

const arr = [
    [12, "AAA"],
    [58, "BBB"],
    [28, "CCC"],
    [18, "DDD"]
  ];

  let arr1 = arr.toSorted();
  let arr2 = arr.toSorted((a, b) => a[0] - b[0]);
  let arr3 = arr.toSorted((a, b) => a[1] - b[1]);

  console.log(arr1);
  console.log(arr2);
  console.log(arr3);

Comments

0

I recently wrote a database program where CSV files are read in and parsed to arrays of arrays (or a 2 dimensional array if you will). The program runs SQL commands on the data, so I had to write a function for sorting by ascending or descending and also by numeric or string. Certainly the function could be more terse, but I prefer to be as clear as possible.

Note that I make a hard copy of the original data, and return a new array. The new array can then be assigned to the original array if you'd like. I prefer this over in place sorting, but that is a matter of preference.

function orderData(arrays, colIndex, dataType = "STRING", direction = "ASC") {
    let newArrays = JSON.parse(JSON.stringify(arrays));//make hard copy
    newArrays.sort(sortFunction);//in place sorting

    function sortFunction(a, b) {//the sort function
        if (dataType === "STRING") {
            if (a[colIndex].toString() < b[colIndex].toString()) {
                return -1;
            }
            if (a[colIndex].toString() > b[colIndex].toString()) {
                return 1;
            }
            return 0;
        }
        else {
            if (Number(a[colIndex]) < Number(b[colIndex])) {
                return -1;
            }
            if (Number(a[colIndex]) > Number(b[colIndex])) {
                return 1;
            }
            return 0;
        }
    }

    if (direction === "DESC") {//reverse if called for
        newArrays.reverse();
    }
    
    return newArrays;
}

Here is an example of it in use:

let array = [[12, "AAA"], [58, "BBB"], [28, "CCC"], [18, "DDD"]];

console.log(array);
console.log();
console.log(orderData(array, 0, "NUMBER", "ASC"));
console.log(orderData(array, 0, "NUMBER", "DESC"));
console.log(orderData(array, 1, "STRING", "ASC"));
console.log(orderData(array, 1, "STRING", "DESC"));

And here are the results:

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.