26

Using JavaScript, I would like to know how to sort lexicographically an array of objects based on a string value in each object.

Consider:

[
 {
    "name" : "bob",
    "count" : true
    "birthday" : 1972
 },
      {
    "name" : "jill",
    "count" : false
    "birthday" : 1922
 },
      {
    "name" : "Gerald",
    "count" : true
    "birthday" : 1920
 }
 ]

How can I sort the array alphabetically by name?

The name values are usernames, so I would like to maintain the letter casing.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Sachin
  • 2,667
  • 9
  • 35
  • 39

4 Answers4

47
var obj = [...];

obj.sort(function(a,b){return a.name.localeCompare(b.name); });

Be aware that this will not take capitalisation into account (so it will order all names beginning with capitals before all those beginning with smalls, i.e. "Z" < "a"), so you might find it relevant to add a toUpperCase() in there.

You can make it more generic as well:

function sortFactory(prop) {
   return function(a,b){ return a[prop].localeCompare(b[prop]); };
}

obj.sort(sortFactory('name')); // sort by name property
obj.sort(sortFactory('surname')); // sort by surname property

And even more generic if you pass the comparator to the factory...

davin
  • 44,863
  • 9
  • 78
  • 78
  • 1
    Use `toLocaleUpperCase`/`toLocaleLowerCase` instead of `toUpperCase`/`toLowerCase`. – Roy Tinker Jun 06 '18 at 22:52
  • 4
    This answer no longer holds true (at least on current chrome dev console). `["a", "A", "b", "B"].sort((a,b)=>{return a.localeCompare(b)})` expected to be `["A", "B", "a", "b"]` but returns `["a", "A", "b", "B"]` – user3240644 Oct 25 '18 at 04:00
  • what @user3240644 said. `'aaA'.localeCompare('aAA')` returns `-1` which sorts `aaA` before `aAA` which is incorrect in the case of lexicographic order – orpheus Aug 18 '20 at 16:37
3

This will do it:

arr.sort(function(a, b) {
    return a.name.localeCompare(b.name);
});
jabclab
  • 14,786
  • 5
  • 54
  • 51
  • thanks for the response, however I forgot to specify that name is actually a username in my data's case, so I want to maintain the casing that is supplied – Sachin Dec 16 '11 at 21:10
  • No problem; I've updated my code. Glad it's sorted via @davin's answer. – jabclab Dec 16 '11 at 21:16
1

Using comparison

arr.sort(function (a, b) {return a.name.toLowerCase() > b.name.toLowerCase()})

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String#Comparing_strings

Cesar Canassa
  • 18,659
  • 11
  • 66
  • 69
0

I read in this post sort array lexicographically in javascript to just use sort directly and not localeCompare and this seems to do the trick.

localeCompare does not sort lexicographically.

'aaA'.localeCompare('aAA') returns -1 which sorts aaA before aAA. In lex, capitals come first, so it should be ['aAA', 'aaA']

You can do something like this to handle a few cases.

export default function sortLex ({ arr, prop, reverse }) {
  let sorted
  if (prop) {
    sorted = arr.sort(sortFactory(prop))
  } else sorted = arr.sort(sort)

  return reverse ? sorted.reverse() : sorted
}

function sort (a, b) {
  if (a < b) {
    return -1
  }
  if (a === b) {
    return 0
  }
  if (a > b) {
    return 1
  }
}

function sortFactory (prop) {
  return (a, b) => {
    return sort(a[prop], b[prop])
  }
}
orpheus
  • 1,060
  • 2
  • 15
  • 23