64

I have an array that contains several arrays and I would like to order the arrays based on a certain string within those arrays.

var myArray = [
                [1, 'alfred', '...'],
                [23, 'berta', '...'],
                [2, 'zimmermann', '...'],
                [4, 'albert', '...'],
              ];

How can I sort it by the name so that albert comes first and zimmermann comes last?

I know how I would do it if I could use the integer for sorting but the string leaves me clueless.

Thank for your help! :)

dmnkhhn
  • 1,013
  • 1
  • 10
  • 18
  • 2
    http://stackoverflow.com/questions/2301856/how-to-sort-an-array-of-objects-based-on-a-the-length-of-a-nested-array-in-javasc is not dissimilar (though not a duplicate). The accepted answer to that question should help you here, though. – Lightness Races in Orbit Mar 25 '11 at 16:29

6 Answers6

105

This can be achieved by passing a supporting function as an argument to the Array.sort method call.

Something like this:

 function Comparator(a, b) {
   if (a[1] < b[1]) return -1;
   if (a[1] > b[1]) return 1;
   return 0;
 }

 var myArray = [
   [1, 'alfred', '...'],
   [23, 'berta', '...'],
   [2, 'zimmermann', '...'],
   [4, 'albert', '...'],
 ];

 myArray = myArray.sort(Comparator);
 console.log(myArray);
dakab
  • 5,379
  • 9
  • 43
  • 67
Martin Milan
  • 6,346
  • 2
  • 32
  • 44
  • Thanks Martin, that is working nicely. However, I have problems with names that are lowercase, those are sorted differently from names that start with the same uppercase letter. – dmnkhhn Mar 26 '11 at 23:24
  • 3
    In that case, use the toUpperCase method of the strings (a[1].toUpperCase() and b[1].toUpperCase) in the Comparator method instead. That will make the sort case insensitive – Martin Milan Mar 28 '11 at 08:19
  • OT, but in many languages (Perl, Ruby, PHP, etc) there is a "spaceship operator" which natively compares and returns -1, 0, or 1 (as per your Comparator method). At the rate ES copies ideas, I would expect it to land in Babel soon. – SamGoody May 01 '20 at 09:00
40

You can still use array.sort() with a custom function. Inside the function, simply compare the element that you want to use as your key. For you example, you could use:

myArray.sort(function(a, b) { 
    return a[1] > b[1] ? 1 : -1;
});
user456584
  • 86,427
  • 15
  • 75
  • 107
vhallac
  • 13,301
  • 3
  • 25
  • 36
  • I think you forgot the `return` – wong2 Mar 25 '11 at 17:13
  • This does not handle equal strings (i.e., it does not return either -1, 1, or 0. @Martin Milan's reply is a better one – Aleadam Mar 25 '11 at 17:36
  • 1
    @Aleadam In theory, you are correct. The comparator is not within the required specs. However, in practice, this works just well enough if you don't care about elements with equal keys being swapped during the sort algorithm. For large arrays, this solution may end up being slower - depending on the implementation of array.sort(). But I need to return 1 or -1, at least. Editing answer. – vhallac Mar 25 '11 at 18:05
  • 2
    so if you need to leave elements in place if equal: `return a[1] == b[1] ? 0 : (a[1] > b[1] ? 1 : -1);` – gordon Feb 05 '16 at 17:33
15

There´s an easier way now:

myArray = myArray.sort(function(a, b) {
    return a[1].localeCompare(b[1]);
})

It is case insensitive too.

Source: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

andyrandy
  • 72,880
  • 8
  • 113
  • 130
  • "cannot find function localeCompare in object" –  Oct 07 '15 at 03:21
  • your array elements must be strings, not objects – andyrandy Oct 07 '15 at 07:21
  • yeah, I've tried converting numbers to strings and still get messed up results. http://stackoverflow.com/questions/33004116/how-do-i-pre-sort-numbers-and-not-screw-up-the-formatting –  Oct 08 '15 at 01:25
9

In ES6 one might do the relatively pithy:

myArray.sort(([a], [b]) => a.localeCompare(b))

or

myArray.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)

The helpful/modern bits being the => lambda operator, and the [X] argument destructuring.

Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343
7

Awesome! Compound sort on first element, second element and then third, all ascending in this example, would be

myArray=myArray.sort(function(a,b){
    retVal=0;
    if(a[0]!=b[0]) retVal=a[0]>b[0]?1:-1;
    else if(a[1]!=b[1]) retVal=a[1]>b[1]?1:-1;
    else if(a[2]!=b[2]) retVal=a[2]>b[2]?1:-1;
    return retVal
});

(multiple sort on more than one column)

gordon
  • 1,152
  • 1
  • 12
  • 18
  • 1
    can this be done dynamically based on array length – gjonte Dec 09 '22 at 11:26
  • I haven't played with dynamic array length, but I'd head in direction of `retVal=0; var lenA=a.length; var lenB=b.length; var toLen=Math.min(lenA,lenB); for(i=0;ib[i]?1:-1;} return retVal;` (ps Sorry not to see for so long.) – gordon Jan 10 '23 at 16:01
  • This assumes the ordering of the elements of your arrays matches the hierarchy of comparing the elements. If you need to bounce comparisons around among the elements, I suppose you could try passing that order in as another argument. – gordon Jan 10 '23 at 16:10
0

Kept getting issues with the solutions posted here. For a simple sorter of simple strings inside an array, I used this:

arr = ["aaa","abc","aba"]
arr.sort((a, b) => a.localeCompare(b));
console.log(arr);
//['aaa','aba','abc']
Capagris
  • 3,811
  • 5
  • 30
  • 44