I have an array of JavaScript objects:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

How can I sort them by the value of last_nom in JavaScript?

I know about sort(a,b), but that only seems to work on strings and numbers. Do I need to add a toString method to my objects?

share|improve this question
1  
This script allows you to do just that unless you want to write your own comparison function or sorter: thomasfrank.se/sorting_things.html – Baversjo Jul 15 '09 at 3:31
    
Now, can anyone post how to do this via an insertion sort? – Ray Jun 14 '13 at 21:44
8  
either first_name or prénom ;=) – walv Jul 18 '14 at 12:52
2  
my upvote made it 1000 :D – JerryGoyal Sep 25 '16 at 17:36

27 Answers 27

up vote 1822 down vote accepted

It's easy enough to write your own comparison function:

function compare(a,b) {
  if (a.last_nom < b.last_nom)
    return -1;
  if (a.last_nom > b.last_nom)
    return 1;
  return 0;
}

objs.sort(compare);

Or inline (c/o Marco Demaio):

objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} ); 
share|improve this answer
255  
Or inline: objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} ); – Marco Demaio Feb 24 '10 at 18:29
13  
60  
return a.last_nom.localeCompare(b.last_nom) will work, too. – Cerbrus Feb 14 '13 at 10:37
65  
for those looking for a sort where the field is numeric, the compare function body: return a.value - b.value; (ASC) – Andre Figueiredo Jan 8 '14 at 12:06
5  
@Cerbrus localeCompare is important when using accented characters in foreign languages, and more elegant as well. – Marcos Lima Jun 1 '16 at 16:38

You can also create a dynamic sort function that sorts objects by their value that you pass:

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

So you can have an array of objects like this:

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

...and it will work when you do:

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

Multiple Parameters

You can use the function below to generate sort functions with multiple sort parameters.

function dynamicSortMultiple() {
    /*
     * save the arguments object as it will be overwritten
     * note that arguments object is an array-like object
     * consisting of the names of the properties to sort by
     */
    var props = arguments;
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length;
        /* try getting a different result from 0 (equal)
         * as long as we have extra properties to compare
         */
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i])(obj1, obj2);
            i++;
        }
        return result;
    }
}

Which would enable you to do something like this:

People.sort(dynamicSortMultiple("Name", "-Surname"));

Adding It To The Prototype

(Implementation which is just below is inspired from Mike R's answer)

I wouldn't recommend changing a native object prototype but just to give an example so you can implement it on your own objects (For the environments that support it, you can also use Object.defineProperty as shown in the next section, which at least doesn't have the negative side-effect of being enumerable, as described at the last part)

Prototype implementation would be something like the following (Here's a working example):

//Don't just copy-paste this code. You will break the "for-in" loops
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Array.prototype.sortBy = function() {
        return this.sort(_dynamicSortMultiple.apply(null, arguments));
    }
}();

The "OK" Way Of Adding It To The Prototype

If you're targeting IE v9.0 and up then, as I previously mentioned, use Object.defineProperty like this (working example):

//Won't work below IE9, but totally safe otherwise
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Object.defineProperty(Array.prototype, "sortBy", {
        enumerable: false,
        writable: true,
        value: function() {
            return this.sort(_dynamicSortMultiple.apply(null, arguments));
        }
    });
}();

This can be an acceptable compromise until the bind operator arrives.

All those prototype fun enables this:

People.sortBy("Name", "-Surname");

You Should Read This

If you use the direct prototype access method (Object.defineProperty is fine) and other code does not check hasOwnProperty, kittens die! Ok, to be honest, no harm comes to any kitten really but probably things will break and every other developer in your team will hate you:

evil

See that last "SortBy"? Yeah. Not cool. Use Object.defineProperty where you can, and leave the Array.prototype alone otherwise.

share|improve this answer
    
Please note that property names in JavaScript can be any string and if you have properties starting with a "-" (extremely unlikely and probably not a good idea), you'll need to modify the dynamicSort function to use something else as a reverse sort indicator. – Ege Özcan Jan 10 '13 at 15:18
    
Great solution! – Donald Powell Oct 23 '14 at 17:52

underscore.js

use underscore, its small and awesome...

sortBy_.sortBy(list, iterator, [context]) Returns a sorted copy of list, ranked in ascending order by the results of running each value through iterator. Iterator may also be the string name of the property to sort by (eg. length).

var objs = [ 
  { first_nom: 'Lazslo',last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine'  },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortedObjs = _.sortBy( objs, 'first_nom' );
share|improve this answer
12  
David, could you edit the answer to say, var sortedObjs = _.sortBy( objs, 'first_nom' );. objs will not be sorted itself as a result of this. The function will return a sorted array. That would make it more explicit. – Jess Jan 9 '14 at 4:01
5  
To reverse sort: var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse(); – Erdal G. Jan 31 '16 at 10:43
1  
This should be the most voted answer. Seriously, don't implement every single helper manually, just use underscore.js. – Adrian Lopez Jul 24 '16 at 4:39
2  
or lodash - better performance. – Harley Alexander Jul 26 '16 at 6:34

Don't get why people make it so complicated:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

For stricter engines:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

Swap the operator to have it sorted by reverse alphabetical order.

share|improve this answer
3  
This is actually not correct as the function used in sort should return -1, 0, or 1 but the above function returns a boolean. The sort works fine in chrome but fails in PhantomJS for example. See code.google.com/p/phantomjs/issues/detail?id=1090 – schup Apr 22 '14 at 15:05
    
Some engines account for stupidity, this way was kind of exploiting that. I've updated my reply with a proper version. – p3lim Apr 22 '14 at 19:23
    
I love to code, I hate to type. One line beats everyone! – iGanja Feb 11 '15 at 21:33
3  
I'd suggest editing to take out the first version. Its more succinct so looks more attractive, but it doesn't work, at least not reliably. If someone tries it in one browser and it works, they may not even realise they have a problem (especially if they haven't read the comments). The second version works properly so there is really no need for the first. – Simon Mar 11 '16 at 15:01
2  
@Simon I really appreciated having the "slightly wrong" version first, since the stricter implementation takes a few seconds to parse and understand and would be much harder without it. – Aaron Sherman Jun 24 '16 at 16:50

In ES6/ES2015 or later you can do this way:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
share|improve this answer
5  
this has been available since JS 1.1, the fat arrow piece to this is the ES6/2015 piece. But still very useful, and best answer in my opinion – Jon Harding Feb 22 '16 at 20:30
2  
Upvote this answer. – cchamberlain May 10 '16 at 18:55
    
just awesome, one more question how do i reverse sort it? – Pratik Kelwalkar May 25 '16 at 13:36
2  
@PratikKelwalkar: if you need reverse it just switch a and b comparison: objs.sort((a, b) => b.last_nom.localeCompare(a.last_nom)); – Vlad Bezden May 26 '16 at 18:24
1  
Thank you very much, this worked a treat for a simple issue I was facing. Kudos for the simplicity, I was not aware of this! – Jon D Jun 10 '16 at 10:09

If you have duplicate last names you might sort those by first name-

obj.sort(function(a,b){
  if(a.last_nom< b.last_nom) return -1;
  if(a.last_nom >b.last_nom) return 1;
  if(a.first_nom< b.first_nom) return -1;
  if(a.first_nom >b.first_nom) return 1;
  return 0;
});
share|improve this answer
7  
That a< b a >b formatting is interesting. – Dodekeract Jan 26 '16 at 1:51

Simple and quick solution to this problem using prototype inheritance:

Array.prototype.sortBy = function(p) {
  return this.slice(0).sort(function(a,b) {
    return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
  });
}

Example / Usage

objs = [{age:44,name:'vinay'},{age:24,name:'deepak'},{age:74,name:'suresh'}];

objs.sortBy('age');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]

objs.sortBy('name');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]

Update: No longer modifies original array.

share|improve this answer
5  
It dosn't just return another array. but actually sorts the original one!. – Vinay Aggarwal Jul 21 '12 at 5:43
    
If you want to make sure you are using a natural sort with numbers (i.e., 0,1,2,10,11 etc...) use parseInt with the Radix set. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… so: return (parseInt(a[p],10) > parseInt(b[p],10)) ? 1 : (parseInt(a[p],10) < parseInt(b[p],10)) ? -1 : 0; – Paul May 11 '15 at 19:14
    
@codehuntr Thanks for correcting it. but i guess instead of making sort function to do this sensitization, it's better if we make a separate function to fix data types. Because sort function can't not tell which property will contain what kind of data. :) – Vinay Aggarwal May 21 '15 at 16:55

Instead of using a custom comparison function, you could also create an object type with custom toString() method (which is invoked by the default comparison function):

function Person(firstName, lastName) {
    this.firtName = firstName;
    this.lastName = lastName;
}

Person.prototype.toString = function() {
    return this.lastName + ', ' + this.firstName;
}

var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();
share|improve this answer

Example Usage:

objs.sort(sortBy('last_nom'));

Script:

/**
 * @description 
 * Returns a function which will sort an
 * array of objects by the given key.
 * 
 * @param  {String}  key
 * @param  {Boolean} reverse
 * @return {Function}     
 */
function sortBy(key, reverse) {

  // Move smaller items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveSmaller = reverse ? 1 : -1;

  // Move larger items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  var moveLarger = reverse ? -1 : 1;

  /**
   * @param  {*} a
   * @param  {*} b
   * @return {Number}
   */
  return function(a, b) {
    if (a[key] < b[key]) {
      return moveSmaller;
    }
    if (a[key] > b[key]) {
      return moveLarger;
    }
    return 0;
  };

}
share|improve this answer

Sorting (more) Complex Arrays of Objects

Since you probably encounter more complex data structures like this array, I would expand the solution.

TL;DR

Are more pluggable version based on @ege-Özcan's very lovely answer.

Problem

I encountered the below and couldn't change it. I also did not want to flatten the object temporarily. Nor did I want to use underscore / lodash, mainly for performance reasons and the fun to implement it myself.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

Goal

The goal is to sort it primarily by People.Name.name and secondarily by People.Name.surname

Obstacles

Now, in the base solution uses bracket notation to compute the properties to sort for dynamically. Here, though, we would have to construct the bracket notation dynamically also, since you would expect some like People['Name.name'] would work - which doesn't.

Simply doing People['Name']['name'], on the other hand, is static and only allows you to go down the n-th level.

Solution

The main addition here will be to walk down the object tree and determine the value of the last leaf, you have to specify, as well as any intermediary leaf.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
//   { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
//   { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]

// same logic as above, but strong deviation for dynamic properties 
function dynamicSort(properties) {
  var sortOrder = 1;
  // determine sort order by checking sign of last element of array
  if(properties[properties.length - 1][0] === "-") {
    sortOrder = -1;
    // Chop off sign
    properties[properties.length - 1] = properties[properties.length - 1].substr(1);
  }
  return function (a,b) {
    propertyOfA = recurseObjProp(a, properties)
    propertyOfB = recurseObjProp(b, properties)
    var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
    return result * sortOrder;
  };
}

/**
 * Takes an object and recurses down the tree to a target leaf and returns it value
 * @param  {Object} root - Object to be traversed.
 * @param  {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
 * @param  {Number} index - Must not be set, since it is implicit.
 * @return {String|Number}       The property, which is to be compared by sort.
 */
function recurseObjProp(root, leafs, index) {
  index ? index : index = 0
  var upper = root
  // walk down one level
  lower = upper[leafs[index]]
  // Check if last leaf has been hit by having gone one step too far.
  // If so, return result from last step.
  if (!lower) {
    return upper
  }
  // Else: recurse!
  index++
  // HINT: Bug was here, for not explicitly returning function
  // http://stackoverflow.com/a/17528613/3580261
  return recurseObjProp(lower, leafs, index)
}

/**
 * Multi-sort your array by a set of properties
 * @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
 * @return {Number} Number - number for sort algorithm
 */
function dynamicMultiSort() {
  var args = Array.prototype.slice.call(arguments); // slight deviation to base

  return function (a, b) {
    var i = 0, result = 0, numberOfProperties = args.length;
    // REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
    // Consider: `.forEach()`
    while(result === 0 && i < numberOfProperties) {
      result = dynamicSort(args[i])(a, b);
      i++;
    }
    return result;
  }
}

Example

Working example on JSBin

share|improve this answer
    
Why? This is not the answer to original question and "the goal" could be solved simply with People.sort((a,b)=>{ return a.Name.name.localeCompare(b.Name.name) || a.Name.surname.localeCompare(b.Name.surname) }) – Tero Tolonen May 3 '16 at 16:02

additional desc params for Ege Özcan code

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }   
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}
share|improve this answer

Acording your example, you need to sort by two fields (last name, first name), rather then one. You can use Alasql library to make this sort in one line:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

Try this example at jsFiddle.

share|improve this answer
1  
nice answer, had never expected could that exist. – IgniteCoders Jun 5 '15 at 12:01

Combining Ege's dynamic solution with Vinay's idea, you get a nice robust solution:

Array.prototype.sortBy = function() {
    function _sortByAttr(attr) {
        var sortOrder = 1;
        if (attr[0] == "-") {
            sortOrder = -1;
            attr = attr.substr(1);
        }
        return function(a, b) {
            var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    function _getSortFunc() {
        if (arguments.length == 0) {
            throw "Zero length arguments not allowed for Array.sortBy()";
        }
        var args = arguments;
        return function(a, b) {
            for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
                result = _sortByAttr(args[i])(a, b);
            }
            return result;
        }
    }
    return this.sort(_getSortFunc.apply(null, arguments));
}

Usage:

// Utility for printing objects
Array.prototype.print = function(title) {
    console.log("************************************************************************");
    console.log("**** "+title);
    console.log("************************************************************************");
    for (var i = 0; i < this.length; i++) {
        console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
    }
}

// Setup sample data
var arrObj = [
    {FirstName: "Zach", LastName: "Emergency", Age: 35},
    {FirstName: "Nancy", LastName: "Nurse", Age: 27},
    {FirstName: "Ethel", LastName: "Emergency", Age: 42},
    {FirstName: "Nina", LastName: "Nurse", Age: 48},
    {FirstName: "Anthony", LastName: "Emergency", Age: 44},
    {FirstName: "Nina", LastName: "Nurse", Age: 32},
    {FirstName: "Ed", LastName: "Emergency", Age: 28},
    {FirstName: "Peter", LastName: "Physician", Age: 58},
    {FirstName: "Al", LastName: "Emergency", Age: 51},
    {FirstName: "Ruth", LastName: "Registration", Age: 62},
    {FirstName: "Ed", LastName: "Emergency", Age: 38},
    {FirstName: "Tammy", LastName: "Triage", Age: 29},
    {FirstName: "Alan", LastName: "Emergency", Age: 60},
    {FirstName: "Nina", LastName: "Nurse", Age: 54}
];

//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
share|improve this answer
1  
Thanks for the idea! By the way, please do not encourage people to change the Array Prototype (see the warning at the end of my example). – Ege Özcan May 10 '13 at 14:51

A simple way:

objs.sort(function(a,b) {
  return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});

See that '.toLowerCase()' is necessary to prevent erros in comparing strings.

share|improve this answer

There are many good answers here, but I would like to point out that they can be extended very simply to achieve a lot more complex sorting. The only thing you have to do is to use the OR operator to chain comparision functions like this:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Where fn1, fn2, ... are the sort functions which return [-1,0,1]. This results in "sorting by fn1", "sorting by fn2" which is pretty much equal to ORDER BY in SQL.

This solution is based on the behaviour of || operator which evaluates to the first evaluated expression which can be converted to true.

The simplest form has only one inlined function like this:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Having two steps with last_nom,first_nom sort order would look like this:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

A generic comparision function could be something like this:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

This function could be extended to support numeric fields, case sensitity, arbitary datatypes etc.

You can them use it with chaining them by sort priority:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

The point here is that pure JavaScript with functional approach can take you a long way without external libraries or complex code. It is also very effective, since no string parsing have to be done

share|improve this answer

I know this question is too old, but I didn't see any implementation similar to mine.
This version is based on the Schwartzian transform idiom.

function sortByAttribute(array, ...attrs) {
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    }
    return result;
  })
  .map(item => item.src);
}

Here's an example how to use it:

let games = [
  { name: 'Pako',              rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));
share|improve this answer
1  
Very smart and cool solution! – Sp0tlight Jan 5 at 15:23

You may need to convert them to the lower case in order to prevent from confusion.

objs.sort(function (a,b) {

var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()

if (nameA < nameB)
  return -1;
if (nameA > nameB)
  return 1;
return 0;  //no sorting

})
share|improve this answer
function compare(propName) {
    return function(a,b) {
        if (a[propName] < b[propName])
            return -1;
        if (a[propName] > b[propName])
            return 1;
        return 0;
    };
}

objs.sort(compare("last_nom"));
share|improve this answer
1  
Please consider editing your post to add more explanation about what your code does and why it will solve the problem. An answer that mostly just contains code (even if it's working) usually wont help the OP to understand their problem. – Drenmi Oct 29 '15 at 18:16
objs.sort(function(a,b){return b.last_nom>a.last_nom})
share|improve this answer
1  
Perfect, thanks – madprops Feb 20 at 8:40
    
Actually it didn't seem to work, had to use the accepted answer. It wasn't sorting correctly. – madprops Feb 21 at 11:15

One more option:

var someArray = [...];

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

someArray.sort(generateSortFn('name', true));

sorts ascending by default.

share|improve this answer
    
This solution makes for clean code. Works great. – Todd Moses Nov 30 '16 at 18:14
    
Slightly changed version for sorting by multiple fields is here if needed: stackoverflow.com/questions/6913512/… – Ravshan Samandarov Dec 1 '16 at 12:37

I Just enhanced Ege Özcan's dynamic sort to dive deep inside objects. If Data looks like this:

obj = [
    {
        a: { a: 1, b: 2, c: 3 },
        b: { a: 4, b: 5, c: 6 }
    },
    { 
        a: { a: 3, b: 2, c: 1 },
        b: { a: 6, b: 5, c: 4 }
}];

and if you want to sort it over a.a property I think my enhancement helps very well. I add new functionality to objects like this:

Object.defineProperty(Object.prototype, 'deepVal', {
    enumerable: false,
    writable: true,
    value: function (propertyChain) {
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) {
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        }
        return parent;
    }
});

and changed _dynamicSort's return function:

return function (a,b) {
        var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
        return result * sortOrder;
    }

And now you can sort by a.a. this way:

obj.sortBy('a.a');

See Commplete script in JSFiddle

share|improve this answer

This is a simple problem, don't know why people have such complex solution.
A simple sort function (based on quick-sort algorithm):

function sortObjectsArray(objectsArray, sortKey)
        {
            // Quick Sort:
            var retVal;

            if (1 < objectsArray.length)
            {
                var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // middle index
                var pivotItem = objectsArray[pivotIndex];                    // value in the middle index
                var less = [], more = [];

                objectsArray.splice(pivotIndex, 1);                          // remove the item in the pivot position
                objectsArray.forEach(function(value, index, array)
                {
                    value[sortKey] <= pivotItem[sortKey] ?                   // compare the 'sortKey' proiperty
                        less.push(value) :
                        more.push(value) ;
                });

                retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
            }
            else
            {
                retVal = objectsArray;
            }

            return retVal;
        }

Use example:

var myArr = 
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];
myArr = sortObjectsArray(myArr, 'idx');
share|improve this answer
4  
How is implementing quick sort in js a simple solution? Simple algorithm but not a simple solution. – Andrew Nov 23 '15 at 22:46
    
It simple since it don't use any outer libraries and it don't change the object's prototype. In my opinion, the length of the code don't have direct impact on the code's complexity – Gil Epshtain Nov 24 '15 at 12:02
2  
Well, let me try with different words: How reinventing the wheel is a simple solution? – Roberto14 Dec 9 '15 at 17:36

Using xPrototype: https://github.com/reduardo7/xPrototype/blob/master/README.md#sortbycol1-col2-coln

var o = [ 
  { Name: 'Lazslo', LastName: 'Jamf'     },
  { Name: 'Pig',    LastName: 'Bodine'   },
  { Name: 'Pirate', LastName: 'Prentice' },
  { Name: 'Pag',    LastName: 'Bodine'   }
];


// Original
o.each(function (a, b) { console.log(a, b); });
/*
 0 Object {Name: "Lazslo", LastName: "Jamf"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Pirate", LastName: "Prentice"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pag", LastName: "Bodine"}
 1 Object {Name: "Pig", LastName: "Bodine"}
 2 Object {Name: "Lazslo", LastName: "Jamf"}
 3 Object {Name: "Pirate", LastName: "Prentice"}
*/


// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pig", LastName: "Bodine"}
 3 Object {Name: "Pag", LastName: "Bodine"}
*/


// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
 0 Object {Name: "Pirate", LastName: "Prentice"}
 1 Object {Name: "Lazslo", LastName: "Jamf"}
 2 Object {Name: "Pag", LastName: "Bodine"}
 3 Object {Name: "Pig", LastName: "Bodine"}
*/
share|improve this answer

I came into problem of sorting array of objects, with changing priority of values, basically I want to sort array of peoples by their Age, and then by surname - or just by surname, name. I think that this is most simple solution compared to another answers.

it' is used by calling sortPeoples(['array', 'of', 'properties'], reverse=false)

///////////////////////example array of peoples ///////////////////////

var peoples = [
    {name: "Zach", surname: "Emergency", age: 1},
    {name: "Nancy", surname: "Nurse", age: 1},
    {name: "Ethel", surname: "Emergency", age: 1},
    {name: "Nina", surname: "Nurse", age: 42},
    {name: "Anthony", surname: "Emergency", age: 42},
    {name: "Nina", surname: "Nurse", age: 32},
    {name: "Ed", surname: "Emergency", age: 28},
    {name: "Peter", surname: "Physician", age: 58},
    {name: "Al", surname: "Emergency", age: 58},
    {name: "Ruth", surname: "Registration", age: 62},
    {name: "Ed", surname: "Emergency", age: 38},
    {name: "Tammy", surname: "Triage", age: 29},
    {name: "Alan", surname: "Emergency", age: 60},
    {name: "Nina", surname: "Nurse", age: 58}
];



//////////////////////// Sorting function /////////////////////
function sortPeoples(propertyArr, reverse) {
        function compare(a,b) {
            var i=0;
            while (propertyArr[i]) {
                if (a[propertyArr[i]] < b[propertyArr[i]])  return -1;
                if (a[propertyArr[i]] > b[propertyArr[i]])  return 1;
                i++;
            }
            return 0;
            }
        peoples.sort(compare);
        if (reverse){
            peoples.reverse();
        }
    };

////////////////end of sorting method///////////////
function printPeoples(){
  $('#output').html('');
peoples.forEach( function(person){
 $('#output').append(person.surname+" "+person.name+" "+person.age+"<br>");
} )
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
  <html>
  <body>
<button onclick="sortPeoples(['surname']); printPeoples()">sort by ONLY by surname ASC results in mess with same name cases</button><br>
<button onclick="sortPeoples(['surname', 'name'], true); printPeoples()">sort by surname then name DESC</button><br>
<button onclick="sortPeoples(['age']); printPeoples()">sort by AGE ASC. Same issue as in first case</button><br>
<button onclick="sortPeoples(['age', 'surname']); printPeoples()">sort by AGE and Surname ASC. Adding second field fixed it.</button><br>
        
    <div id="output"></div>
    </body>
  </html>

share|improve this answer
    
array of peoples :( – RaisingAgent Feb 14 at 14:17
// Sort Array of Objects

// Data
var booksArray = [
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

// Property to Sort By
var args = "last_nom";

// Function to Sort the Data by given Property
function sortByProperty(property) {
    return function (a, b) {
        var sortStatus = 0,
            aProp = a[property].toLowerCase(),
            bProp = b[property].toLowerCase();
        if (aProp < bProp) {
            sortStatus = -1;
        } else if (aProp > bProp) {
            sortStatus = 1;
        }
        return sortStatus;
    };
}

// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));

console.log("sortedArray: " + JSON.stringify(sortedArray) );

Console log output:

"sortedArray: 
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"

Adapted based on this source: http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/

share|improve this answer

This will sort a two level nested array by the property passed to it in alpha numeric order.

function sortArrayObjectsByPropAlphaNum(property) {
    return function (a,b) {
        var reA = /[^a-zA-Z]/g;
        var reN = /[^0-9]/g;
        var aA = a[property].replace(reA, '');
        var bA = b[property].replace(reA, '');

        if(aA === bA) {
            var aN = parseInt(a[property].replace(reN, ''), 10);
            var bN = parseInt(b[property].replace(reN, ''), 10);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
        } else {
            return a[property] > b[property] ? 1 : -1;
        }
    };
}

Usage:

objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));
share|improve this answer

So here is one sorting algorithm which can sort in any order , throughout array of any kind of objects , without the restriction of datatype comparison ( i.e. Number , String )

function smoothSort(items,prop,reverse) {  
    var length = items.length;
    for (var i = (length - 1); i >= 0; i--) {
        //Number of passes
        for (var j = (length - i); j > 0; j--) {
            //Compare the adjacent positions
            if(reverse){
              if (items[j][prop] > items[j - 1][prop]) {
                //Swap the numbers
                var tmp = items[j];
                items[j] = items[j - 1];
                items[j - 1] = tmp;
            }
            }

            if(!reverse){
              if (items[j][prop] < items[j - 1][prop]) {
                  //Swap the numbers
                  var tmp = items[j];
                  items[j] = items[j - 1];
                  items[j - 1] = tmp;
              }
            }
        }
    }

    return items;
}
  • the first argument items is the array of objects ,

  • prop is the key of the object on which you want to sort ,

  • reverse is a boolean parameter which on being true results in Ascending order and in false it returns descending order.

share|improve this answer

protected by Pankaj Parkar Oct 16 '15 at 12:16

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.