1263

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:  "[email protected]",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};
0

23 Answers 23

2028

Shortest possible code with ES6!

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

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

Sign up to request clarification or add additional context in comments.

8 Comments

People should be aware this may be slower with large data sets. I'd recommend benchmarking if this is critical code
how to inverse order?
@chovy users.sort((a, b) => -1 * a.firstname.localeCompare(b.firstname)) just multiply it by -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.
@chovy users.sort((a, b)=> b.firstname.localeCompare(a.firstname)) just switch the order of things you pass to localeCompare
|
1509

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.

15 Comments

For those coming in at a later date, Mrchief's answer is better because it's case insensitive.
This code will only work on english speaking countries. In other countries you should be using ovunccetin's answer with localeCompare.
In ternary: users.sort(function(a, b) { return (a > b ? 1 : (a === b ? 0 : -1)) })
Dont forget to use the same text casing (e.g. 'toLowerCase()' ).
it is buggy as won't work for string with different cases. You need to lowercase as well comparison strings
|
419

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

8 Comments

String.localeCompare isn't supports Safari and IE < 11 :)
@CORSAIR it is supported, it is just the second and third parameter that aren't supported.
@CORSAIR the usage in the example is supported in all major IE browsers: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. LocaleCompare also takes into account capitalization, so I think this implementation should be considered the best practice.
users.sort((a, b) => a.firstname.localeCompare(b.firstname)) // Short n sweet ES6 version!
tanks bro. in ES6 use users.sort((a, b) => a.name.localeCompare(b.name))
|
416

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

7 Comments

When sorting strings 'toLowerCase()' is very important - capital letters could affect your sort.
In case anyone else is wondering what the toLowerCase impacts, it's not much: 'a'>'A' //true 'z'>'a' //true 'A'>'z' //false
@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 yeah that's a good case man. 'Z' < 'a' // true and 'z' < 'a' // false
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.
|
46

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

Comments

45

Nice little ES6 one liner:

users.sort((a, b) => a.firstname !== b.firstname ? a.firstname < b.firstname ? -1 : 1 : 0);

4 Comments

This one is incomplete since it doesn't handle equal values properly.
Of course, thanks for spotting that, I have added a check for matching values
not bad I guess if you really want it all on one line, nested ternaries get confusing for readability though
@SamLogan this is really helpful, thank you for you contribution.
22

lodash and 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()})

1 Comment

the second example involves returning strings. Does sortBy detect the returned values are strings and thus performs an alphabetical sorting? Thanks
21

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

Comments

20

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.

Comments

18

A more compact notation:

user.sort(function(a, b){
    return a.firstname === b.firstname ? 0 : a.firstname < b.firstname ? -1 : 1;
})

3 Comments

it's more compact but violates its contract: sign(f(a, b)) =-sign(f(b, a)) (for a = b)
return a.firstname == b.firstname should use === for completeness
user.sort((a,b) => a.firstname > b.firstname || -1)
12

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: "[email protected]",
    firstname: "Anna",
    id: 318,
    last_avatar: "<null>",
    last_message: "<null>",
    lastname: "Nickson",
    nickname: "anny",
  },
  {
    bio: "<null>",
    email: "[email protected]",
    firstname: "Senad",
    id: 318,
    last_avatar: "<null>",
    last_message: "<null>",
    lastname: "Nickson",
    nickname: "anny",
  },
  {
    bio: "<null>",
    email: "[email protected]",
    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;
});

4 Comments

why return 0 at the end?
=, when strings are same
but in that case shouldn't the else be removed? Otherwise that return 0 will never be read
that is not "else", it's "else if"
11

Shortest

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

8 Comments

the sort function should return -1,0,1. this one only returns -1,1.
@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)
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements.
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 ?
|
8

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

Comments

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

Comments

5

in simply words you can use this method

users.sort(function(a,b){return a.firstname < b.firstname ? -1 : 1});

Comments

5

Inspired from this answer,

users.sort((a,b) => (a.firstname  - b.firstname));

6 Comments

Wrong wrong wrong! You don't get a valid result if you subtract strings in Javascript.
@xjcl did you run my code? This is working perfectly. jsfiddle.net/5uh34njg
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.
This gives NaN unless firstname is a number
I have no idea how this answer got so many upvotes. It's flat-out wrong. Even the provided supporting jsfiddle doesn't work.
|
5

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

Comments

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

Comments

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

Comments

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!

2 Comments

Not a proper answer because it only performs less than and greater than checks and not the equal check.
it also does not bring enything new to the table, compared to any of the answers that have been sitting there since ~2011.
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;
};

Comments

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)

Comments

-1

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;

})

1 Comment

Same answer as the one by Mrchief. With the further disadvantage that the toLowerCase is done four times per comparison instead of two times.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.