1183

I got an array (see below for one object in the array) that I need to sort by firstname using JavaScript. How can I do it?

var user = {
   bio: null,
   email:  "user@domain.example",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Jonathan Clark
  • 19,726
  • 29
  • 111
  • 175

23 Answers23

1845

Shortest possible code with ES6!

users.sort((a, b) => a.firstname.localeCompare(b.firstname))

String.prototype.localeCompare() basic support is universal!

technogeek1995
  • 3,185
  • 2
  • 31
  • 52
Nachiketha
  • 21,705
  • 3
  • 24
  • 32
  • 3
    People should be aware this may be slower with large data sets. I'd recommend benchmarking if this is critical code – Yoshi Feb 15 '21 at 02:06
  • 3
    how to inverse order? – chovy Mar 04 '22 at 04:10
  • 13
    @chovy `users.sort((a, b) => -1 * a.firstname.localeCompare(b.firstname))` just multiply it by `-1` – AlexMelw Mar 04 '22 at 14:18
  • 1
    If you want to use this to sort strings that may contain numbers, it does not work correctly. For example, `'7'.localeCompare('16')` returns `1`. – hb20007 May 20 '22 at 16:26
  • 1
    For strings with numbers to sort them out by the numbers (such as bank accounts, car plates, etc.): `users.sort((a, b) => a.firstname.replace(/\D/g, '').localeCompare(b.firstname.replace(/\D/g, '')));` – Daniel Danielecki Oct 04 '22 at 11:42
  • 1
    @chovy `users.sort((a, b)=> b.firstname.localeCompare(a.firstname))` just switch the order of things you pass to localeCompare – SleekPanther Apr 29 '23 at 22:52
  • for case insensitivity `(a, b) => a.firstname.toLowerCase().localeCompare(b.firstname.toLowerCase())` – Reza Aug 16 '23 at 09:12
1481

Suppose you have an array users. You may use users.sort and pass a function that takes two arguments and compare them (comparator)

It should return

  • something negative if first argument is less than second (should be placed before the second in resulting array)
  • something positive if first argument is greater (should be placed after second one)
  • 0 if those two elements are equal.

In our case if two elements are a and b we want to compare a.firstname and b.firstname

Example:

users.sort(function(a, b){
    if(a.firstname < b.firstname) { return -1; }
    if(a.firstname > b.firstname) { return 1; }
    return 0;
})

This code is going to work with any type.

Note that in "real life"™ you often want to ignore case, correctly sort diacritics, weird symbols like ß, etc. when you compare strings, so you may want to use localeCompare. See other answers for clarity.

Nenad Zivkovic
  • 18,221
  • 6
  • 42
  • 55
RiaD
  • 46,822
  • 11
  • 79
  • 123
  • Who would have thought strings could be sorted just by their value? Sweeeeet. – AlbertEngelB Jan 30 '13 at 19:16
  • 87
    For those coming in at a later date, Mrchief's answer is better because it's case insensitive. – mlienau Apr 01 '13 at 14:19
  • 21
    This code will only work on english speaking countries. In other countries you should be using [ovunccetin's answer with `localeCompare`](http://stackoverflow.com/a/16481400/3713). – Spoike Jul 06 '13 at 05:47
  • 5
    In ternary: `users.sort(function(a, b) { return (a > b ? 1 : (a === b ? 0 : -1)) })` – awhie29urh2 Aug 09 '13 at 06:25
  • 2
    Dont forget to use the same text casing (e.g. 'toLowerCase()' ). – MarzSocks Jan 09 '14 at 13:08
  • `users.sort(function(a, b) { return a.firstname < b.firstname ? -1 : a.firstname > b.firstname ? 1 : 0; })` – SpYk3HH Apr 30 '15 at 13:55
  • Are you applying sort to the object user, or array? array should be named users for better understanding – jscripter Jun 15 '15 at 12:21
  • @commenters: Rewritten answers, added mention of "correct" sorting methods – RiaD Jan 08 '16 at 17:07
  • What if a numerical field needs to be included along with the string field? @RiaD Suppose firstname + id. But id 10 should not be less than 5 as string – Nisha Aug 08 '16 at 09:03
  • @Nisha, check firstname first, if they not equal return appropriately, if the equal, compare ids – RiaD Aug 08 '16 at 10:40
  • 1
    it is buggy as won't work for string with different cases. You need to lowercase as well comparison strings – Kanan Farzali Mar 28 '19 at 17:06
  • It is not working with the last record comes under array. It sort all the data perfect but doesn't sort last data. In my country list, Canada is coming at last (In array also, Canada is the last value). Please help to fix this. – Nishant Jun 06 '19 at 10:27
  • your sort would be more efficient with an `else if` than with 2 tests `if > AND if < ` one excluding the other on each loop pass – Pipo Nov 20 '19 at 18:38
  • wut? Code after return will not execute, so there's no difference. – RiaD Nov 20 '19 at 21:54
410

Something like this:

array.sort(function(a, b){
 var nameA = a.name.toLowerCase(), nameB = b.name.toLowerCase();
 if (nameA < nameB) //sort string ascending
  return -1;
 if (nameA > nameB)
  return 1;
 return 0; //default return value (no sorting)
});
radbyx
  • 9,352
  • 21
  • 84
  • 127
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • 52
    When sorting strings 'toLowerCase()' is very important - capital letters could affect your sort. – MarzSocks Jan 09 '14 at 13:06
  • 5
    In case anyone else is wondering what the toLowerCase impacts, it's not much: `'a'>'A' //true` `'z'>'a' //true` `'A'>'z' //false` – SimplGy Jan 14 '14 at 18:13
  • 17
    @SimplGy I'd argue that its impact is a bit more than you're giving it credit for. For instance, as stated in the comments to the accepted answer, it's important to know whether or not your sort function will sort the string `'Zebra'` higher than the string `'apple'`, which it will do if you don't use the `.toLowerCase()`. – PrinceTyke Aug 04 '15 at 12:34
  • 1
    @PrinceTyke yeah that's a good case man. `'Z' < 'a' // true` and `'z' < 'a' // false` – SimplGy Aug 05 '15 at 14:59
  • 2
    All valid points and I'd say sorting is always a "it depends" kind of thing. If you're sorting by names, case sensitivity may not matter. In other cases it might. Regardless, I think adopting to one's specific situation is not hard once you get the core idea. – Mrchief Aug 05 '15 at 15:02
  • I like this answer because it is very clear. And for the people that don't know why (and how) this works -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort which is actually a great website for JS. Thanks! – Combine Nov 21 '16 at 14:35
  • While using the `.toLowerCase()`, ensure your value is not null before calling it – Bosco Mar 24 '20 at 21:17
406

If compared strings contain unicode characters you can use localeCompare function of String class like the following:

users.sort(function(a,b){
    return a.firstname.localeCompare(b.firstname);
})
Spoike
  • 119,724
  • 44
  • 140
  • 158
ovunccetin
  • 8,443
  • 5
  • 42
  • 53
  • 3
    String.localeCompare isn't supports Safari and IE < 11 :) – CORSAIR Jun 11 '14 at 08:21
  • 13
    @CORSAIR it is supported, it is just the second and third parameter that aren't supported. – Codler Nov 25 '14 at 12:24
  • 7
    @CORSAIR the usage in the example is supported in all major IE browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare. LocaleCompare also takes into account capitalization, so I think this implementation should be considered the best practice. – Matt Jensen Aug 17 '15 at 22:23
  • 11
    users.sort((a, b) => a.firstname.localeCompare(b.firstname)) // Short n sweet ES6 version! – Nachiketha Aug 07 '17 at 09:51
  • 7
    tanks bro. in ES6 use `users.sort((a, b) => a.name.localeCompare(b.name))` – Mohmmad Ebrahimi Aval Oct 11 '18 at 15:50
  • 1
    This, by far, is the most simplest answer! – Ajay Gupta Oct 25 '18 at 11:00
  • Might want to wrap `a.firstname` in a `String` constructor to avoid null type errors/intellisense support too. – rmolinamir Aug 19 '19 at 18:17
  • @RobertMolina String should be used with care as it may result in unwanted results, `String(null) === 'null'`. Depending on the case there may be other unexpected values like numbers. `String(a.firstname ?? '').localCompare(b.firstname ?? '')` may be generally safer. – Estus Flask Oct 05 '20 at 11:05
45

Nice little ES6 one liner:

users.sort((a, b) => a.firstname !== b.firstname ? a.firstname < b.firstname ? -1 : 1 : 0);
Sam Logan
  • 3,343
  • 2
  • 17
  • 13
45

We can use localeCompare but need to check the keys as well for falsey values

The code below will not work if one entry has missing lname.

obj.sort((a, b) => a.lname.localeCompare(b.lname))

So we need to check for falsey value like below

let obj=[
{name:'john',lname:'doe',address:'Alaska'},
{name:'tom',lname:'hopes',address:'California'},
{name:'harry',address:'Texas'}
]
let field='lname';
console.log(obj.sort((a, b) => (a[field] || "").toString().localeCompare((b[field] || "").toString())));

OR

we can use lodash , its very simple. It will detect the returned values i.e whether number or string and do sorting accordingly .

import sortBy from 'lodash/sortBy';
sortBy(obj,'name')

https://lodash.com/docs/4.17.5#sortBy

sumit
  • 15,003
  • 12
  • 69
  • 110
20

underscorejs offers the very nice _.sortBy function:

_.sortBy([{a:1},{a:3},{a:2}], "a")

or you can use a custom sort function:

_.sortBy([{a:"b"},{a:"c"},{a:"a"}], function(i) {return i.a.toLowerCase()})
iConnor
  • 19,997
  • 14
  • 62
  • 97
Peter T.
  • 2,927
  • 5
  • 33
  • 40
  • 2
    the second example involves returning strings. Does `sortBy` detect the returned values are strings and thus performs an alphabetical sorting? Thanks – superjos Nov 10 '14 at 21:01
19

In case we are sorting names or something with special characters, like ñ or áéíóú (commons in Spanish) we could use the params locales (es for spanish in this case ) and options like this:

let user = [{'firstname': 'Az'},{'firstname': 'Áb'},{'firstname':'ay'},{'firstname': 'Ña'},{'firstname': 'Nz'},{'firstname': 'ny'}];


user.sort((a, b) => a.firstname.localeCompare(b.firstname, 'es', {sensitivity: 'base'}))


console.log(user)

The oficial locale options could be found here in iana, es (spanish), de (German), fr (French). About sensitivity base means:

Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A.

Emeeus
  • 5,072
  • 2
  • 25
  • 37
17

A more compact notation:

user.sort(function(a, b){
    return a.firstname === b.firstname ? 0 : a.firstname < b.firstname ? -1 : 1;
})
biniam
  • 8,099
  • 9
  • 49
  • 58
James Andrews
  • 3,257
  • 3
  • 31
  • 45
13

I'm surprised no one mentioned Collators. You shouldn't use localeCompare unless you have to as it has significantly worse performance

const collator = new Intl.Collator('zh-CN'); // Chinese Simplified for example

function sortAsc(a: string, b: string) {
  return collator.compare(a, b)
}

function sortDesc(a: string, b: string) {
  return collator.compare(b, a);
}
Dominic
  • 62,658
  • 20
  • 139
  • 163
11

Basically you can sort arrays with method sort, but if you want to sort objects then you have to pass function to sort method of array, so I will give you an example using your array

user = [
  {
    bio: "<null>",
    email: "user@domain.example",
    firstname: "Anna",
    id: 318,
    last_avatar: "<null>",
    last_message: "<null>",
    lastname: "Nickson",
    nickname: "anny",
  },
  {
    bio: "<null>",
    email: "user@domain.example",
    firstname: "Senad",
    id: 318,
    last_avatar: "<null>",
    last_message: "<null>",
    lastname: "Nickson",
    nickname: "anny",
  },
  {
    bio: "<null>",
    email: "user@domain.example",
    firstname: "Muhamed",
    id: 318,
    last_avatar: "<null>",
    last_message: "<null>",
    lastname: "Nickson",
    nickname: "anny",
  },
];

var ar = user.sort(function (a, b) {
  var nA = a.firstname.toLowerCase();
  var nB = b.firstname.toLowerCase();

  if (nA < nB) return -1;
  else if (nA > nB) return 1;
  return 0;
});
Mohamad Shiralizadeh
  • 8,329
  • 6
  • 58
  • 93
Senad Meškin
  • 13,597
  • 4
  • 37
  • 55
9

try

users.sort((a,b)=> (a.firstname>b.firstname)*2-1)

var users = [
  { firstname: "Kate", id: 318, /*...*/ },
  { firstname: "Anna", id: 319, /*...*/ },
  { firstname: "Cristine", id: 317, /*...*/ },
]

console.log(users.sort((a,b)=> (a.firstname>b.firstname)*2-1) );
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • 3
    the sort function should return -1,0,1. this one only returns -1,1. – Radu Luncasu Jun 26 '19 at 10:02
  • @RaduLuncasu - can you provide test data (users array) which shows that above solution gives wrong result? (as far I know, missing zero is no problem) – Kamil Kiełczewski Jun 26 '19 at 10:05
  • If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. – Radu Luncasu Jun 27 '19 at 12:11
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort – Radu Luncasu Jun 27 '19 at 12:12
  • @RaduLuncasu ok, but that informations doesn't mean that zero is mandatory. The best way to show it is prepare data which not works - but as far I know this is impossible - e.g. `[9,8,7,6,5,1,2,3].sort((a,b) => a – Kamil Kiełczewski Jun 27 '19 at 12:40
  • 1
    Why are you using an array of numbers ? Why not try : [{firstname: "anna", id:1}, {firstname: "anna", id:2}] and see how the lack of 0 for equality will change the sorting of the array for no reason ? – Radu Luncasu Jun 27 '19 at 12:47
  • @RaduLuncasu but OP needs on output sorted array - so botch cases `[{firstname: "anna", id:1}, {firstname: "anna", id:2}] ` and `[{firstname: "anna", id:2}, {firstname: "anna", id:1}]` are valid solutions (the only valid criterion given by OP is sorted by firstname). – Kamil Kiełczewski Jun 27 '19 at 12:49
  • I disagree, shouldn't change sorting for equal comparison, hence the JavaScript implementation of the compare function which uses 0 for that case. – Radu Luncasu Jun 27 '19 at 12:52
7

also for both asec and desc sort, u can use this : suppose we have a variable SortType that specify ascending sort or descending sort you want:

 users.sort(function(a,b){
            return   sortType==="asc"? a.firstName.localeCompare( b.firstName): -( a.firstName.localeCompare(  b.firstName));
        })
Ghazaleh Javaheri
  • 1,829
  • 19
  • 25
7

A generalized function can be written like below

    function getSortedData(data, prop, isAsc) {
        return data.sort((a, b) => (a[prop] < b[prop] ? -1 : 1) * (isAsc ? 1 : -1));
   }

you can pass the below parameters

  1. The data which you want to sort
  2. The property in the data by it should be sorted
  3. The last parameter is of boolean type. It checks if you want to sort by ascending or by descending
Santosh
  • 1,027
  • 13
  • 12
6

Inspired from this answer,

users.sort((a,b) => (a.firstname  - b.firstname));
  • 4
    Wrong wrong wrong! You don't get a valid result if you subtract strings in Javascript. – xjcl Jul 13 '20 at 13:03
  • @xjcl did you run my code? This is working perfectly. https://jsfiddle.net/5uh34njg/ – Isuru Siriwardana Jul 15 '20 at 04:45
  • 1
    It's not working. The users are just output in the order of the input. Plus the field name you used there was `firstname` when it's actually `name` in your users object. – xjcl Jul 15 '20 at 12:56
  • 1
    This gives NaN unless firstname is a number – gildniy Nov 05 '20 at 23:25
  • I have no idea how this answer got so many upvotes. It's flat-out wrong. Even the provided supporting jsfiddle doesn't work. – Benjamin Jun 07 '22 at 20:08
4

in simply words you can use this method

users.sort(function(a,b){return a.firstname < b.firstname ? -1 : 1});
FarukT
  • 1,560
  • 11
  • 25
4

Just for the record, if you want to have a named sort-function, the syntax is as follows:

let sortFunction = (a, b) => {
 if(a.firstname < b.firstname) { return -1; }
 if(a.firstname > b.firstname) { return 1; }
 return 0;
})
users.sort(sortFunction)

Note that the following does NOT work:

users.sort(sortFunction(a,b))
Katinka Hesselink
  • 3,961
  • 4
  • 20
  • 26
3

You can use this for objects

transform(array: any[], field: string): any[] {
return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);}
Andre Coetzee
  • 1,260
  • 3
  • 20
  • 34
2

Pushed the top answers into a prototype to sort by key.

Array.prototype.alphaSortByKey= function (key) {
    this.sort(function (a, b) {
        if (a[key] < b[key])
            return -1;
        if (a[key] > b[key])
            return 1;
        return 0;
    });
    return this;
};
msponagle
  • 330
  • 1
  • 11
1

You can use the in-built array method - sort. This method takes a callback method as a param



    // custom sort function to be passed as param/callback to the Array's sort method
    function myCustomSort(a, b) {
        return (a.toLowerCase() > b.toLowerCase()) ? 1 : -1;
    }

    // Actual method to be called by entity that needs sorting feature
    function sortStrings() {
        var op = Array.prototype.sort.call(arguments, myCustomSort);
    }

    // Testing the implementation
    var sortedArray = sortStrings("Burger", "Mayo1", "Pizza", "boxes", "Apples", "Mayo");
    console.log(sortedArray); //["Apples", "boxes", "Burger", "Mayo", "Mayo1", "Pizza"]


Key Points to be noted for understanding this code.

  1. The custom method, in this case, myCustomSort, should return +1 or -1 for each element pair(from the input array) comparison.
  2. Use toLowerCase()/toUpperCase() in the custom sorting callback method so that case difference does not affect the correctness of the sorting process.

I hope this is clear enough explanation. Feel free to comment if you think, more info is needed.

Cheers!

shanky
  • 6,283
  • 1
  • 11
  • 15
  • Not a proper answer because it only performs less than and greater than checks and not the equal check. – Steel Brain Mar 14 '16 at 04:15
  • it also does not bring enything new to the table, compared to any of the answers that have been sitting there since ~2011. – amenthes Oct 16 '16 at 12:46
1

My implementation, works great in older ES versions:

sortObject = function(data) {
    var keys = Object.keys(data);
    var result = {};

    keys.sort();

    for(var i = 0; i < keys.length; i++) {
        var key = keys[i];

        result[key] = data[key];
    }

    return result;
};
eXtreme
  • 244
  • 3
  • 18
1

for a two factors sort (name and lastname):

users.sort((a, b) => a.name.toLowerCase() < b.name.toLowerCase() ? -1 : a.name.toLowerCase() > b.name.toLowerCase() ? 1 : a.lastname.toLowerCase() < b.lastname.toLowerCase() ? -1 : a.lastname.toLowerCase() > b.lastname.toLowerCase() ? 1 : 0)
asma
  • 599
  • 1
  • 7
  • 19
0

You can use something similar, to get rid of case sensitive

users.sort(function(a, b){

  //compare two values
  if(a.firstname.toLowerCase() < b.firstname.toLowerCase()) return -1;
  if(a.firstname.toLowerCase() > b.firstname.toLowerCase()) return 1;
  return 0;

})
Chris Forrence
  • 10,042
  • 11
  • 48
  • 64
SAN_WEB
  • 25
  • 3
  • 8
    Same answer as the one by Mrchief. With the further disadvantage that the toLowerCase is done four times per comparison instead of two times. – amenthes Oct 16 '16 at 12:43