javascript - JavaScrip的对象数组排序的属性值

  显示原文与译文双语对照的内容

我有一个JavaScript对象数组:


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

如何用JavaScript中的last_nom 值对它们进行排序?

我知道 sort(a,b),但它只对字符串和数字有用。 是否需要向对象添加toString方法?

时间:

编写你自己的比较函数很容易:


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);

你还可以创建一个动态排序函数,根据你通过的值对对象排序:


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;
 }
}

这样你就可以拥有一个类似这样的对象数组:


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

- - 并且它将工作当你做:


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

多个参数

你可以使用下面的函数来生成具有多个排序参数的排序函数。


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;
 }
}

这将使你能够执行如下操作:


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

将它添加到 Prototype

( 在下面的实现灵感来自于 R)

在最后一部分 ), 我不建议你更改本机对象 Prototype,但这些就是给一个示例,你可以实现它自己的对象 ( 上为环境支持它的,你还可以使用 Object.defineProperty 见下一节所述,它不具有的负面副作用的摆弄一个原生的Prototype对象,

Prototype实现类似于以下( 是一个工作示例 ):


//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));
 }
}();

将它添加到Prototype的正确方法

如果你要瞄准 IE v9.0和起来,然后,就像我前面提到的,使用 Object.defineProperty 喜欢这里( 工作示例 ):


//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));
 }
 });
}();

所有这些Prototype乐趣启用了:


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

你应该读读这个

如果使用直接Prototype访问方法( 对象。defineProperty是好) 和其他代码,并不检查服务器的,小猫会死 ! 好吧,老实说,任何一个小猫都不会伤害到你,但是你的团队中的所有开发人员都会讨厌你:

evil

看到最后的"sortby"了是的。 不正常。使用 Object.defineProperty,在你可以的地方,将 Array.prototype 单独保留。

underscore.js

使用下划线,它的小而可怕。。

sortBy_.sortBy(list, iterator, [context] ) 返回排序的列表的排序副本,以升序排序通过迭代器运行每个值的结果。 迭代器也可以是要排序的属性的字符串名称( 例如。 长度) 。


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' );

不要知道人们为什么这么复杂:


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

对于更严格的引擎:


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

交换运算符以使它的按字母顺序排序。

如果你有重复的姓氏,你可以按名字排序。


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;
});

你还可以使用自定义 toString() 方法( 由默认比较函数调用) 创建一个对象类型,而不是使用自定义比较函数:


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();

使用Prototype继承解决这个问题的简单快速的解决方案:


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;
 });
}

示例/用法


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"}]

更新: 不再修改原始数组。

使用方法的示例:


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

脚本:


/**
 * @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;
 };

}


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;
 }
}

将动态规划解决方案和vinay的思想结合起来,你可以得到一个很好的解决方案:


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));
}

使用方法:


//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");

...