I have an array of JavaScript objects:
var objs = [ { first_nom: 'Laszlo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];How can I sort them by the value oflast_nom in JavaScript?
I know aboutsort(a,b), but that only seems to work on strings and numbers. Do I need to add atoString() method to my objects?
- 5Case sensitive or case insensitive sort?Peter Mortensen– Peter Mortensen2022-12-10 22:18:01 +00:00CommentedDec 10, 2022 at 22:18
61 Answers61
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((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0))Or simplified for numeric (c/o Andre Figueiredo):
objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort9 Comments
return a.last_nom.localeCompare(b.last_nom) will work, too.return a.value - b.value; (ASC)charCodeAt, then use the numeric inline above for a more concise one liner:objs.sort((a,b) => a.last_nom.charCodeAt(0) - b.last_nom.charCodeAt(0));. This avoids the ugly nested ternary.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) { /* next line works with strings and numbers, * and you may want to customize it to your needs */ 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"));Actually this already answers the question. Below part is written because many people contacted me, complaining thatit doesn't work with multiple parameters.
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"));Subclassing Array
For the lucky among us who can use ES6, which allows extending the native objects:
class MyArray extends Array { sortBy(...args) { return this.sort(dynamicSortMultiple(...args)); }}That would enable this:
MyArray.from(People).sortBy("Name", "-Surname");5 Comments
InES6/ES2015 or later you can do it this way:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));Prior to ES6/ES2015
objs.sort(function(a, b) { return a.last_nom.localeCompare(b.last_nom)});3 Comments
localeCompare. You can use the standard> operator - like mentioned in the answer by @muasif80 -stackoverflow.com/a/67992215/6908282Use Underscore.js]. It’s small and awesome...
sortBy_.sortBy(list, iterator, [context]) Returns a sorted copy oflist, ranked in ascending order by the results of running each valuethrough iterator. Iterator may also be the string name of the propertyto 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');8 Comments
var sortedObjs = _.sortBy( objs, 'first_nom' );.objs willnot be sorted itself as a result of this. The function willreturn a sorted array. That would make it more explicit.var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>var sortedObjs = _.sortBy( objs, 'first_nom' ); or if you want it in a different order:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );Case sensitive
arr.sort((a, b) => a.name > b.name ? 1 : -1);Case Insensitive
arr.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1);Useful Note
If no change in order (in case of the same strings) then the condition> will fail and-1 will be returned. But if strings are same then returning 1 or -1 will result in correct output
The other option could be to use>= operator instead of>
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];// Define a couple of sorting callback functions, one with hardcoded sort key and the other with an argument sort keyconst sorter1 = (a, b) => a.last_nom.toLowerCase() > b.last_nom.toLowerCase() ? 1 : -1;const sorter2 = (sortBy) => (a, b) => a[sortBy].toLowerCase() > b[sortBy].toLowerCase() ? 1 : -1;objs.sort(sorter1);console.log("Using sorter1 - Hardcoded sort property last_name", objs);objs.sort(sorter2('first_nom'));console.log("Using sorter2 - passed param sortBy='first_nom'", objs);objs.sort(sorter2('last_nom'));console.log("Using sorter2 - passed param sortBy='last_nom'", objs);6 Comments
-1 and1 for eg: from1 : -1 to-1 : 1(a, b) to (b, a) :)1 &-1 more straight forward and logical.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;});3 Comments
b should come aftera in the array. If a positive number is returned, it meansa should come afterb. If0 is returned, it means they are considered equal. You can always read the documentation:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…1, 0, -1 before I asked this here. I just wasn't finding the info I needed.As of 2018 there is a much shorter and elegant solution. Just use.Array.prototype.sort().
Example:
var items = [ { name: 'Edward', value: 21 }, { name: 'Sharpe', value: 37 }, { name: 'And', value: 45 }, { name: 'The', value: -12 }, { name: 'Magnetic', value: 13 }, { name: 'Zeros', value: 37 }];// sort by valueitems.sort(function (a, b) { return a.value - b.value;});3 Comments
a.value - b.value used to compare the object's attributes (numbers in this case) can be adopted for the various times of data. For example, regex can be used to compare each pair of the neighboringstrings.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.
5 Comments
.slice(0) is to make a shallow copy of the array.Old answer that is not correct:
arr.sort((a, b) => a.name > b.name)UPDATE
FromBeauchamp's comment:
arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))More readable format:
arr.sort((a, b) => { if (a.name < b.name) return -1 return a.name > b.name ? 1 : 0})Without nested ternaries:
arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))Explanation:Number() will casttrue to1 andfalse to0.
5 Comments
arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))arr.sort((a, b) => a.name > b.name ? 1 : -1 will not work? For Strings i have tested this works great. If you want case insensitive then usea.name.toLowerCase() andb.name.toLowerCase()You can useEasiest Way:Lodash
(https://lodash.com/docs/4.17.10#orderBy)
This method is like_.sortBy except that it allows specifying the sort orders of the iteratees to sort by. If orders is unspecified, all values are sorted in ascending order. Otherwise, specify an order of "desc" for descending or "asc" for ascending sort order of corresponding values.
Arguments
collection (Array|Object): The collection to iterate over.[iteratees=[_.identity]] (Array[]|Function[]|Object[]|string[]): The iteratees to sort by.[orders] (string[]): The sort orders of iteratees.
Returns
(Array): Returns the new sorted array.
var _ = require('lodash');var homes = [ {"h_id":"3", "city":"Dallas", "state":"TX", "zip":"75201", "price":"162500"}, {"h_id":"4", "city":"Bevery Hills", "state":"CA", "zip":"90210", "price":"319250"}, {"h_id":"6", "city":"Dallas", "state":"TX", "zip":"75000", "price":"556699"}, {"h_id":"5", "city":"New York", "state":"NY", "zip":"00010", "price":"962500"} ]; _.orderBy(homes, ['city', 'state', 'zip'], ['asc', 'desc', 'asc']);1 Comment
Lodash (a superset ofUnderscore.js).
It's good not to add a framework for every simple piece of logic, but relying on well tested utility frameworks can speed up development and reduce the amount of bugs.
Lodash produces very clean code and promotes a morefunctional programming style. In one glimpse, it becomes clear what the intent of the code is.
The OP's issue can simply be solved as:
const sortedObjs = _.sortBy(objs, 'last_nom');More information? For example, we have the following nested object:
const users = [ { 'user': {'name':'fred', 'age': 48}}, { 'user': {'name':'barney', 'age': 36 }}, { 'user': {'name':'wilma'}}, { 'user': {'name':'betty', 'age': 32}}];We now can use the_.property shorthanduser.age to specify the path to the property that should be matched. We will sort the user objects by the nested age property. Yes, it allows for nested property matching!
const sortedObjs = _.sortBy(users, ['user.age']);Want it reversed? No problem. Use_.reverse.
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));Want to combine both usingchain?
const { chain } = require('lodash');const sortedObjs = chain(users).sortBy('user.age').reverse().value();Or when do you preferflow over chain?
const { flow, reverse, sortBy } = require('lodash/fp');const sortedObjs = flow([sortBy('user.age'), reverse])(users);Comments
I haven't seen this particular approach suggested, so here's a terse comparison method I like to use that works for bothstring andnumber types:
const objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];const sortBy = fn => { const cmp = (a, b) => -(a < b) || +(a > b); return (a, b) => cmp(fn(a), fn(b));};const getLastName = o => o.last_nom;const sortByLastName = sortBy(getLastName);objs.sort(sortByLastName);console.log(objs.map(getLastName));Explanation ofsortBy()
sortBy() accepts afn that selects a value from an object to use in comparison, and returns a function that can be passed toArray.prototype.sort(). In this example, we're comparingo.last_nom. Whenever we receive two objects such as
a = { first_nom: 'Lazslo', last_nom: 'Jamf' }b = { first_nom: 'Pig', last_nom: 'Bodine' }we compare them with(a, b) => cmp(fn(a), fn(b)). Given that
fn = o => o.last_nomwe can expand the comparison function to(a, b) => cmp(a.last_nom, b.last_nom). Because of the waylogical OR (||) works in JavaScript,cmp(a.last_nom, b.last_nom) is equivalent to
if (a.last_nom < b.last_nom) return -1;if (a.last_nom > b.last_nom) return 1;return 0;Incidentally, this is called thethree-way comparison "spaceship" (<=>) operator in other languages.
Finally, here's the ES5-compatible syntax without using arrow functions:
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];function sortBy(fn) { function cmp(a, b) { return -(a < b) || +(a > b); } return function (a, b) { return cmp(fn(a), fn(b)); };}function getLastName(o) { return o.last_nom; }var sortByLastName = sortBy(getLastName);objs.sort(sortByLastName);console.log(objs.map(getLastName));4 Comments
-(fa < fb) || +(fa > fb) is a mistake here. That's multiple statements being condensed into one line of code. The alternative, written with anif statement, would be much more readable whilst still being fairly concise. I think it's a mistake to sacrifice readability for prettiness.fa <=> fb.const cmp = (a, b) => -(a < b) || +(a > b);) Think of["ä", "a", "c", "b"].sort(cmp) =>["a", "b", "c", "ä"], whereä is pushed to the end. Instead you should probably update the comparison function to:const cmp = (a, b) => a.localeCompare(b); =>["a", "ä", "b", "c"] Cheers and thanks for the answer ;-)localeCompare removes the ability to sort numbers, and is alsosignificantly slower.Instead of using a custom comparison function, you could also create an object type with customtoString() 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();Comments
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 comparison functions like this:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )Wherefn1,fn2, ... are the sort functions which return [-1,0,1]. This results in "sorting by fn1" and "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 thefirst evaluated expression which can be converted to true.
The simplest form has only one inlined function like this:
// ORDER BY last_nomobjs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )Having two steps withlast_nom,first_nom sort order would look like this:
// ORDER_BY last_nom, first_nomobjs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || a.first_nom.localeCompare(b.first_nom) )A generic comparison 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-sensitivity, arbitrary data types, etc.
You can use them by chaining them by sort priority:
// ORDER_BY last_nom, first_nomobjs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )// ORDER_BY last_nom, first_nom DESCobjs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )// ORDER_BY last_nom DESC, first_nom DESCobjs.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.
Comments
Try this:
Up toES5
// Ascending sortitems.sort(function (a, b) { return a.value - b.value;});// Descending sortitems.sort(function (a, b) { return b.value - a.value;});InES6 and above
// Ascending sortitems.sort((a, b) => a.value - b.value);// Descending sortitems.sort((a, b) => b.value - a.value);3 Comments
Use JavaScriptsort method
Thesort method can be modified to sort anything like an array of numbers, strings and even objects using a compare function.
A compare function is passed as anoptional argument to the sort method.
This compare function accepts 2 arguments generally calleda andb. Based on these 2 arguments you can modify the sort method to work as you want.
- If the compare function returns less than 0, then the
sort()method sortsa at a lower index thanb. Simply a will come before b. - If the compare function returns equal to 0, then the
sort()method leaves the element positions as they are. - If the compare function returns greater than 0, then the
sort()method sortsa at greater index thanb. Simplya will come afterb.
Use the above concept to apply on your object wherea will be your object property.
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];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);console.log(objs)// for better look use console.table(objs)
Comments
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} */const 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. const 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. const moveLarger = reverse ? -1 : 1; /** * @param {*} a * @param {*} b * @return {Number} */ return (a, b) => { if (a[key] < b[key]) { return moveSmaller; } if (a[key] > b[key]) { return moveLarger; } return 0; };};3 Comments
1, 0, -1 are used for sort ordering. Even with your explanation above, which looks very good-- I'm still not quite understanding it. I always think of-1 as when using array length property, i.e.:arr.length = -1 means that the item isn't found. I'm probably mixing things up here, but could you help me understand why digits1, 0, -1 are used to determine order? Thanks.a andb, ifa is greater thanb add 1 to the index ofa and place it behindb, ifa is less thanb, subtract 1 froma and place it in front ofb. Ifa andb are the same, add 0 toa and leave it where it is.Write short code:
objs.sort((a, b) => a.last_nom > b.last_nom ? 1 : -1)7 Comments
1, -1, 0a>b && 1|| -1 is equal toa> b ? 1 : -1, operator&& returns first logicalfalse value, operator|| returns first logicaltrue value.I didn't see any implementation similar to mine. This version is based on theSchwartzian transform idiom.
function sortByAttribute(array, ...attrs) { // Generate an array of predicate-objects containing // 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: 'Mashraki', 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 attributeconsole.log(sortByAttribute(games, 'name'));// Sort by mupltiple attributesconsole.log(sortByAttribute(games, '-rating', 'name'));Comments
Sorting objects withIntl.Collator for the specific case when you wantnatural string sorting (i.e.["1","2","10","11","111"]).
const files = [ {name: "1.mp3", size: 123}, {name: "10.mp3", size: 456}, {name: "100.mp3", size: 789}, {name: "11.mp3", size: 123}, {name: "111.mp3", size: 456}, {name: "2.mp3", size: 789},];const naturalCollator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});files.sort((a, b) => naturalCollator.compare(a.name, b.name));console.log(files);Note: theundefined constructor argument forIntl.Collator represents the locale, which can be an explicit ISO 639-1 language code such asen, or the system default locale whenundefined.
Comments
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 lovelyanswer.
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 byPeople.Name.name and secondarily byPeople.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 likePeople['Name.name'] would work - which doesn't.
Simply doingPeople['Name']['name'], on the other hand, is static and only allows you to go down then-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 // https://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 exampleon JSBin
1 Comment
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 datavar 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 TestsarrObj.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");1 Comment
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));It sorts ascending by default.
3 Comments
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.
3 Comments
objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );Warning!
Using this solution isnot recommended as it does not result in a sorted array. It is being left here for future reference, because the idea is not rare.
objs.sort(function(a,b){return b.last_nom>a.last_nom})1 Comment
This is my take on this:
Theorder parameter is optional and defaults to "ASC" for ascending order.
It works onaccented characters and it's caseinsensitive.
Note: It sorts and returns theoriginal array.
function sanitizeToSort(str) { return str .normalize('NFD') // Remove accented and diacritics .replace(/[\u0300-\u036f]/g, '') // Remove accented and diacritics .toLowerCase() // Sort will be case insensitive ;}function sortByProperty(arr, property, order="ASC") { arr.forEach((item) => item.tempProp = sanitizeToSort(item[property])); arr.sort((a, b) => order === "ASC" ? a.tempProp > b.tempProp ? 1 : a.tempProp < b.tempProp ? -1 : 0 : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ? 1 : 0 ); arr.forEach((item) => delete item.tempProp); return arr;}Snippet
function sanitizeToSort(str) { return str .normalize('NFD') // Remove accented characters .replace(/[\u0300-\u036f]/g, '') // Remove diacritics .toLowerCase() ;}function sortByProperty(arr, property, order="ASC") { arr.forEach((item) => item.tempProp = sanitizeToSort(item[property])); arr.sort((a, b) => order === "ASC" ? a.tempProp > b.tempProp ? 1 : a.tempProp < b.tempProp ? -1 : 0 : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ? 1 : 0 ); arr.forEach((item) => delete item.tempProp); return arr;}const rockStars = [ { name: "Axl", lastname: "Rose" }, { name: "Elthon", lastname: "John" }, { name: "Paul", lastname: "McCartney" }, { name: "Lou", lastname: "Reed" }, { name: "freddie", // Works on lower/upper case lastname: "mercury" }, { name: "Ámy", // Works on accented characters too lastname: "winehouse"}];sortByProperty(rockStars, "name");console.log("Ordered by name A-Z:");rockStars.forEach((item) => console.log(item.name + " " + item.lastname));sortByProperty(rockStars, "lastname", "DESC");console.log("\nOrdered by lastname Z-A:");rockStars.forEach((item) => console.log(item.lastname + ", " + item.name));2 Comments
Given the original example:
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];Sort by multiple fields:
objs.sort(function(left, right) { var last_nom_order = left.last_nom.localeCompare(right.last_nom); var first_nom_order = left.first_nom.localeCompare(right.first_nom); return last_nom_order || first_nom_order;});Notes
a.localeCompare(b)isuniversally supported and returns -1,0,1 ifa<b,a==b,a>brespectively.||in the last line giveslast_nompriority overfirst_nom.- Subtraction works on numeric fields:
var age_order = left.age - right.age; - Negate to reverse order,
return -last_nom_order || -first_nom_order || -age_order;
Comments
A simple function that sorts an array of object by a property:
function sortArray(array, property, direction) { direction = direction || 1; array.sort(function compare(a, b) { let comparison = 0; if (a[property] > b[property]) { comparison = 1 * direction; } else if (a[property] < b[property]) { comparison = -1 * direction; } return comparison; }); return array; // Chainable}Usage:
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: 'Pirate', last_nom: 'Prentice' }];sortArray(objs, "last_nom"); // AscsortArray(objs, "last_nom", -1); // Desc1 Comment
Additional desc parameters forEge Özcan's 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; }}1 Comment
You may need to convert them to the lowercase form 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})Comments
Explore related questions
See similar questions with these tags.










































