问题 在JavaScript中按字符串属性值对对象数组进行排序
我有一个JavaScript对象数组:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
我怎样才能按它的值对它们进行排序 last_nom
在JavaScript?
我知道 sort(a,b)
,但这似乎只适用于字符串和数字。我需要在对象中添加toString方法吗?
8750
2017-07-15 03:17
起源
答案:
编写自己的比较函数很容易:
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);
或内联(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);} );
2716
2017-07-15 03:35
您还可以创建一个动态排序函数,按照您传递的值对对象进行排序:
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"));
将它添加到原型
(下面的实施灵感来自于 迈克R.的 回答)
我不建议更改本机对象原型,只是举一个例子,以便您可以在自己的对象上实现它 (对于支持它的环境,您也可以使用 Object.defineProperty 如下一节所示,至少没有可枚举的负面副作用,如最后一部分所述)
原型实现将类似于以下(这是一个有效的例子):
//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));
}
}();
将其添加到原型的“OK”方式
如果您的目标是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));
}
});
}();
这可能是一个可接受的妥协,直到 绑定运算符 到达。
所有这些原型乐趣都可以实现:
People.sortBy("Name", "-Surname");
你应该读这个
如果你使用直接原型访问方法(Object.defineProperty很好),其他代码不检查 hasOwnProperty,小猫死了!好吧,说实话,任何小猫都没有受到伤害,但可能事情会破裂,团队中的其他开发人员都会讨厌你:

看到最后一个“SortBy”?是啊。不酷。尽可能使用Object.defineProperty,否则单独保留Array.prototype。
650
2018-01-21 15:03
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' );
155
2018-05-10 21:24
不要理解为什么人们会这么复杂:
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;
});
交换运算符以按反向字母顺序排序。
141
2018-01-24 19:35
在ES6 / ES2015或更高版本中,您可以这样做:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
138
2018-01-29 19:44
如果你有重复的姓氏,你可以按名字排序 -
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;
});
51
2017-07-15 04:03
使用原型继承简单快速地解决此问题:
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"}]
更新: 不再修改原始数组。
38
2017-07-10 11:54
您也可以使用自定义创建对象类型,而不是使用自定义比较功能 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();
24
2017-07-15 07:21
这里有很多好的答案,但我想指出它们可以非常简单地扩展以实现更复杂的排序。您唯一需要做的就是使用OR运算符来链接比较函数,如下所示:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
哪里 fn1
, fn2
,...是返回[-1,0,1]的排序函数。这导致“按fn1排序”,“按fn2排序”,这几乎等于SQL中的ORDER BY。
此解决方案基于。的行为 ||
运算符,评估为 首先计算可以转换为true的表达式。
最简单的形式 只有一个内联函数,如下所示:
// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )
有两个步骤 last_nom
,first_nom
排序顺序如下:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
a.first_nom.localeCompare(b.first_nom) )
一般的比较函数 可能是这样的:
// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])
此函数可以扩展为支持数字字段,大小写敏感,任意数据类型等。
您可以通过排序优先级链接它们来使用它:
// 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") )
这里的要点是具有功能方法的纯JavaScript可以在没有外部库或复杂代码的情况下走很长的路。它也非常有效,因为不需要进行字符串解析
14
2018-05-05 11:36