282

Let's say you have a JavaScript class like this

var DepartmentFactory = function(data) {
    this.id = data.Id;
    this.name = data.DepartmentName;
    this.active = data.Active;
}

Let's say you then create a number of instances of that class and store them in an array

var objArray = [];
objArray.push(DepartmentFactory({Id: 1, DepartmentName: 'Marketing', Active: true}));
objArray.push(DepartmentFactory({Id: 2, DepartmentName: 'Sales', Active: true}));
objArray.push(DepartmentFactory({Id: 3, DepartmentName: 'Development', Active: true}));
objArray.push(DepartmentFactory({Id: 4, DepartmentName: 'Accounting', Active: true}));

So I now would have an array of objects created by DepartmentFactory. How would I go about using the array.sort() method to sort this array of objects by the DepartmentName property of each object?

The array.sort() method works just fine when sorting an array of strings

var myarray=["Bob", "Bully", "Amy"];
myarray.sort(); //Array now becomes ["Amy", "Bob", "Bully"]

But how do I make it work with a list of objects?

Luca Kiebel
  • 9,200
  • 6
  • 29
  • 43
jdavis
  • 7,315
  • 12
  • 50
  • 61
  • You can pass a sort function as the first argument to .sort(). – Paul Tomblin Jan 17 '12 at 19:47
  • 2
    Since you're using `DepartmentFactory` as a constructor, create its objects using `new DepartmentFactory`, otherwise the array will be filled with a bunch of `undefined` values. – Anurag Jan 17 '12 at 19:49

14 Answers14

459

you would have to do something like this:

objArray.sort(function(a, b) {
    var textA = a.DepartmentName.toUpperCase();
    var textB = b.DepartmentName.toUpperCase();
    return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
});

note: changing the case (to upper or lower) ensures a case insensitive sort.

Omer Bokhari
  • 54,210
  • 12
  • 43
  • 54
  • 5
    I've come to your answer 50 gazillion times because i can never remember how to do this. FWIW, my Linter always informs me of "gratuitous parentheses around expression": `return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;` Not gonna edit your answer, holding out hope I'll at least remember the linting thing :) – MikeT May 18 '18 at 22:40
  • Found an issue with this code. Use a combination of lower and capital letters. ex. credit_card_no and City. The code does sort the list but words starting with 'c' are not grouped together. – Kedar Aug 21 '19 at 21:55
  • 3
    we can simplify it to return textA.localeCompare(textB); – Taran Feb 04 '21 at 21:47
226

To support unicode:

objArray.sort(function(a, b) {
   return a.DepartmentName.localeCompare(b.DepartmentName);
});
ron tornambe
  • 9,926
  • 7
  • 32
  • 59
  • 12
    For a case-insensitive version, use the following on line 2: `return a.DepartmentName.toLowerCase().localeCompare(b.DepartmentName.toLowerCase());` – Ben Barreth Jan 16 '18 at 16:09
  • 4
    learn something new every day - `localeCompare` is cool and has all browser support for first arg. Not bad! – obzenner Jun 15 '18 at 21:34
  • 9
    @BenBarreth there is no reason to lower-case the strings. the whole point of `localeCompare` is to shunt the work of managing sort logic and locale quirks to the system. If doing a case-insensitive sort is normal for the locale, as it is in english, this will be done for you: `"Z" > 'a' // false` `"Z".localeCompare('a') // 1` If you wish to deviate from the locale's default, you can send along overrides in the `locales` and `options` parameters: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare#Parameters – Jon z Mar 08 '19 at 14:24
  • Just remember that this isn't null safe, need to check to see if "DepartmentName" is an actual string before running this otherwise the sort will fail on a null pointer exception. – Kris Boyd Jun 14 '21 at 20:42
29

Shorter code with ES6

objArray.sort((a, b) => a.DepartmentName.toLowerCase().localeCompare(b.DepartmentName.toLowerCase()))
Ludovic
  • 321
  • 3
  • 9
15
objArray.sort((a, b) => a.DepartmentName.localeCompare(b.DepartmentName))
Neil
  • 7,491
  • 3
  • 49
  • 69
14
var DepartmentFactory = function(data) {
    this.id = data.Id;
    this.name = data.DepartmentName;
    this.active = data.Active;
}

// use `new DepartmentFactory` as given below. `new` is imporatant

var objArray = [];
objArray.push(new DepartmentFactory({Id: 1, DepartmentName: 'Marketing', Active: true}));
objArray.push(new DepartmentFactory({Id: 2, DepartmentName: 'Sales', Active: true}));
objArray.push(new DepartmentFactory({Id: 3, DepartmentName: 'Development', Active: true}));
objArray.push(new DepartmentFactory({Id: 4, DepartmentName: 'Accounting', Active: true}));

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

//objArray.sort(sortOn("id")); // because `this.id = data.Id;`
objArray.sort(sortOn("name")); // because `this.name = data.DepartmentName;`
console.log(objArray);

demo: http://jsfiddle.net/diode/hdgeH/

Diode
  • 23,400
  • 8
  • 39
  • 50
8
// Sorts an array of objects "in place". (Meaning that the original array will be modified and nothing gets returned.)
function sortOn (arr, prop) {
    arr.sort (
        function (a, b) {
            if (a[prop] < b[prop]){
                return -1;
            } else if (a[prop] > b[prop]){
                return 1;
            } else {
                return 0;   
            }
        }
    );
}

//Usage example:

var cars = [
        {make:"AMC",        model:"Pacer",  year:1978},
        {make:"Koenigsegg", model:"CCGT",   year:2011},
        {make:"Pagani",     model:"Zonda",  year:2006},
        ];

// ------- make -------
sortOn(cars, "make");
console.log(cars);

/* OUTPUT:
AMC         : Pacer : 1978
Koenigsegg  : CCGT  : 2011
Pagani      : Zonda : 2006
*/



// ------- model -------
sortOn(cars, "model");
console.log(cars);

/* OUTPUT:
Koenigsegg  : CCGT  : 2011
AMC         : Pacer : 1978
Pagani      : Zonda : 2006
*/



// ------- year -------
sortOn(cars, "year");
console.log(cars);

/* OUTPUT:
AMC         : Pacer : 1978
Pagani      : Zonda : 2006
Koenigsegg  : CCGT  : 2011
*/
bob
  • 6,861
  • 2
  • 44
  • 41
7
objArray.sort( (a, b) => a.id.localeCompare(b.id, 'en', {'sensitivity': 'base'}));

This sorts them alphabetically AND is case insensitive. It's also super clean and easy to read :D

Alissa
  • 71
  • 1
  • 1
  • This is also the only answer which mentions `'sensitivity': 'base'`, which makes a big difference depending on your application [according to MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator). – phantomraa Jul 03 '20 at 05:57
5

DEMO

var DepartmentFactory = function(data) {
    this.id = data.Id;
    this.name = data.DepartmentName;
    this.active = data.Active;
}

var objArray = [];
objArray.push(new DepartmentFactory({Id: 1, DepartmentName: 'Marketing', Active: true}));
objArray.push(new DepartmentFactory({Id: 2, DepartmentName: 'Sales', Active: true}));
objArray.push(new DepartmentFactory({Id: 3, DepartmentName: 'Development', Active: true}));
objArray.push(new DepartmentFactory({Id: 4, DepartmentName: 'Accounting', Active: true}));

console.log(objArray.sort(function(a, b) { return a.name > b.name}));
qwertymk
  • 32,454
  • 27
  • 117
  • 182
2

do it like this

objArrayy.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)
});
console.log(objArray)
nickleefly
  • 3,673
  • 1
  • 25
  • 31
2

Because all of the solutions here were presented without null/undefined safe operations, I handle that this way (you can handle nulls as you see fit):

ES5

objArray.sort(
  function(a, b) {
    var departmentNameA = a.DepartmentName ? a.DepartmentName : '';
    var departmentNameB = b.DepartmentName ? b.DepartmentName : '';

    departmentNameA.localeCompare(departmentNameB);
  }
);

ES6+

objArray.sort(
 (a: DepartmentFactory, b: DepartmentFactory): number => {
   const departmentNameA = a.DepartmentName ? a.DepartmentName : '';
   const departmentNameB = b.DepartmentName ? b.DepartmentName : '';

   departmentNameA.localeCompare(departmentNameB);
 }
);

I have also removed the toLowerCase that others used since localeCompare is case insensitive. Also I prefer to be a bit more explicit on parameters when using Typescript or ES6+ to make it more explicit for future developers.

Kris Boyd
  • 509
  • 7
  • 16
1

Here is a simple function you can use to sort array of objects through their properties; it doesn't matter if the property is a type of string or integer, it will work.

    var cars = [
        {make:"AMC",        model:"Pacer",  year:1978},
        {make:"Koenigsegg", model:"CCGT",   year:2011},
        {make:"Pagani",     model:"Zonda",  year:2006},
    ];

    function sortObjectsByProp(objectsArr, prop, ascending = true) {
        let objectsHaveProp = objectsArr.every(object => object.hasOwnProperty(prop));
        if(objectsHaveProp)    {
            let newObjectsArr = objectsArr.slice();
            newObjectsArr.sort((a, b) => {
                if(isNaN(Number(a[prop])))  {
                    let textA = a[prop].toUpperCase(),
                        textB = b[prop].toUpperCase();
                    if(ascending)   {
                        return textA < textB ? -1 : textA > textB ? 1 : 0;
                    } else {
                        return textB < textA ? -1 : textB > textA ? 1 : 0;
                    }
                } else {
                    return ascending ? a[prop] - b[prop] : b[prop] - a[prop];
                }
            });
            return newObjectsArr;
        }
        return objectsArr;
    }

    let sortedByMake = sortObjectsByProp(cars, "make"); // returns ascending order by its make;
    let sortedByYear = sortObjectsByProp(cars, "year", false); // returns descending order by its year,since we put false as a third argument;
    console.log(sortedByMake);
    console.log(sortedByYear);
-3

After try a little bit on this, and trying to make less loops as possible, I ended up with this solution:

Demo on codepen

const items = [
      {
        name: 'One'
      },
      {
        name: 'Maria is here'
      },
      {
        name: 'Another'
      },
      {
        name: 'Z with a z'
      },
      {
        name: '1 number'
      },
      {
        name: 'Two not a number'
      },
      {
        name: 'Third'
      },
      {
        name: 'Giant'
      }
    ];

    const sorted = items.sort((a, b) => {
      return a[name] > b[name];
    });

    let sortedAlphabetically = {};

    for(var item in sorted) {
      const firstLetter = sorted[item].name[0];
      if(sortedAlphabetically[firstLetter]) {
        sortedAlphabetically[firstLetter].push(sorted[item]);
      } else {
        sortedAlphabetically[firstLetter] = [sorted[item]]; 
      }
    }

    console.log('sorted', sortedAlphabetically);
-3

You have to pass a function that accepts two parameters, compares them, and returns a number, so assuming you wanted to sort them by ID you would write...

objArray.sort(function(a,b) {
    return a.id-b.id;
});
// objArray is now sorted by Id
zconnelly13
  • 264
  • 1
  • 4
  • 11
-4

A simple answer:

objArray.sort(function(obj1, obj2) {
   return obj1.DepartmentName > obj2.DepartmentName;
});

ES6 way:

objArray.sort((obj1, obj2) => {return obj1.DepartmentName > obj2.DepartmentName};

If you need to make it lowercase/uppercase etc, just do that and store that result in a variable than compare that variable. Example:

objArray.sort((obj1, obj2) => {
   var firstObj = obj1.toLowerCase();
   var secondObj = obj2.toLowerCase();
   return firstObj.DepartmentName > secondObj.DepartmentName;
});
Mar
  • 105
  • 3
  • 12