Sort array of objects by string property value in JavaScript
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?
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);} );
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"));
Actually this already answers the question. Below part is written because many people contacted me, complaining that it 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"));
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:
See that last "SortBy"? Yeah. Not cool. Use Object.defineProperty where you can, and leave the Array.prototype alone otherwise.
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' );
链接地址: http://www.djcxy.com/p/422.html