我有一组 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 );
或内联(c/o Marco Demaio):
objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0))
或简化为数字(c/o Andre Figueiredo):
objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort
您还可以创建一个动态排序函数,该函数根据您传递的对象的值对对象进行排序:
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;
}
}
所以你可以有一个这样的对象数组:
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"));
其实这已经回答了这个问题。以下部分是因为很多人联系我,抱怨it doesn't work with multiple 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;
}
}
这将使您能够执行以下操作:
People.sort(dynamicSortMultiple("Name", "-Surname"));
子类化数组
对于我们当中可以使用 ES6 的幸运儿,它允许扩展原生对象:
class MyArray extends Array {
sortBy(...args) {
return this.sort(dynamicSortMultiple(...args));
}
}
这将实现这一点:
MyArray.from(People).sortBy("Name", "-Surname");
在 ES6/ES2015 或更高版本中,您可以这样做:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
在 ES6/ES2015 之前
objs.sort(function(a, b) {
return a.last_nom.localeCompare(b.last_nom)
});
localeCompare
。您可以使用标准的 >
运算符 - 就像@muasif80 的答案中提到的那样 - stackoverflow.com/a/67992215/6908282
使用下划线,它小而真棒......
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' );
var sortedObjs = _.sortBy( objs, 'first_nom' );
。 objs
将不会因此而自行排序。该函数将返回一个排序数组。这将使它更加明确。
var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
Lodash
中为喜欢那个的人提供
var sortedObjs = _.sortBy( objs, 'first_nom' );
或者如果您希望它以不同的顺序:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
区分大小写
arr.sort((a, b) => a.name > b.name ? 1 : -1);
不区分大小写
arr.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1);
有用的说明
如果顺序没有变化(在相同字符串的情况下),则条件 >
将失败并返回 -1
。但是如果字符串相同,则返回 1 或 -1 将导致正确的输出
另一种选择可能是使用 >=
运算符而不是 >
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: '海盗', last_nom: 'Prentice' } ]; // 定义几个排序回调函数,一个带有硬编码排序键,另一个带有参数排序键 const 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("使用 sorter1 - 硬编码排序属性 last_name", objs); objs.sort(sorter2('first_nom')); console.log("使用 sorter2 - 传递参数 sortBy='first_nom'", objs); objs.sort(sorter2('last_nom')); console.log("使用 sorter2 - 传递参数 sortBy='last_nom'", objs);
-1
和 1
交换为例如:从 1 : -1
到 -1 : 1
(a, b) to (b, a)
怎么样 :)
1
& -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;
});
b
应该在数组中的 a
之后。如果返回正数,则表示 a
应该在 b
之后。如果返回 0
,则表示它们被视为相等。您可以随时阅读文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
1, 0, -1
搜索了各种代码片段。我只是没有找到我需要的信息。
截至 2018 年,有一个更短更优雅的解决方案。就用吧。 Array.prototype.sort()。
例子:
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 value
items.sort(function (a, b) {
return a.value - b.value;
});
a.value - b.value
可用于不同时间的数据。例如,正则表达式可用于比较每对相邻的字符串。
使用原型继承简单快速地解决这个问题:
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"}]
更新:不再修改原始数组。
不正确的旧答案:
arr.sort((a, b) => a.name > b.name)
更新
来自 Beauchamp 的评论:
arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
更易读的格式:
arr.sort((a, b) => {
if (a.name < b.name) return -1
return a.name > b.name ? 1 : 0
})
没有嵌套三元组:
arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))
说明:Number()
会将 true
转换为 1
并将 false
转换为 0
。
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
不起作用?对于我已经测试过的字符串,这很好用。如果您希望不区分大小写,请使用 a.name.toLowerCase()
和 b.name.toLowerCase()
Lodash.js(Underscore.js 的超集)
最好不要为每个简单的逻辑添加框架,但是依靠经过良好测试的实用框架可以加快开发速度并减少错误数量。
Lodash 生成非常干净的代码并促进了更函数式的编程风格。一眼就能看出代码的意图是什么。
OP的问题可以简单地解决为:
const sortedObjs = _.sortBy(objs, 'last_nom');
更多信息?例如,我们有以下嵌套对象:
const users = [
{ 'user': {'name':'fred', 'age': 48}},
{ 'user': {'name':'barney', 'age': 36 }},
{ 'user': {'name':'wilma'}},
{ 'user': {'name':'betty', 'age': 32}}
];
我们现在可以使用 _.property 简写 user.age
来指定应该匹配的属性的路径。我们将按嵌套的年龄属性对用户对象进行排序。是的,它允许嵌套属性匹配!
const sortedObjs = _.sortBy(users, ['user.age']);
想要逆转?没问题。使用 _.reverse。
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));
想要使用 chain 将两者结合起来吗?
const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();
或者你什么时候更喜欢 flow 而不是链
const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users);
您可以使用最简单的方法:Lodash
(https://lodash.com/docs/4.17.10#orderBy)
此方法与 _.sortBy
类似,只是它允许指定要排序的迭代对象的排序顺序。如果未指定 orders,则所有值都按升序排序。否则,为相应值的降序指定“desc”或“asc”为升序排序。
论据
集合(数组|对象):要迭代的集合。 [iteratees=[_.identity]] (Array[]|Function[]|Object[]|string[]): 要排序的迭代对象。 [orders] (string[]):迭代的排序顺序。
退货
(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']);
我还没有看到建议的这种特殊方法,所以这是我喜欢使用的一种简洁的比较方法,它适用于 string
和 number
类型:
const objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: '海盗', last_nom: 'Prentice' } ]; const sortBy = fn => { const cmp = (a, b) => -(a < b) || +(a > b);返回 (a, b) => cmp(fn(a), fn(b)); };常量 getLastName = o => o.last_nom;常量 sortByLastName = sortBy(getLastName); objs.sort(sortByLastName); console.log(objs.map(getLastName));
sortBy() 的解释
sortBy()
接受一个 fn
,它从对象中选择一个值以用于比较,并返回一个可以传递给 Array.prototype.sort()
的函数。在本例中,我们比较 o.last_nom
。每当我们收到两个对象时,例如
a = { first_nom: 'Lazslo', last_nom: 'Jamf' }
b = { first_nom: 'Pig', last_nom: 'Bodine' }
我们将它们与 (a, b) => cmp(fn(a), fn(b))
进行比较。鉴于
fn = o => o.last_nom
我们可以将比较函数扩展为 (a, b) => cmp(a.last_nom, b.last_nom)
。由于 logical OR (||
) 在 JavaScript 中的工作方式,cmp(a.last_nom, b.last_nom)
相当于
if (a.last_nom < b.last_nom) return -1;
if (a.last_nom > b.last_nom) return 1;
return 0;
顺便说一下,这在其他语言中称为 three-way comparison "spaceship" (<=>
) operator。
最后,这是不使用箭头函数的 ES5 兼容语法:
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: '海盗', last_nom: 'Prentice' } ];函数 sortBy(fn) { 函数 cmp(a, b) { 返回 -(a < b) || +(a > b); } 返回函数 (a, b) { 返回 cmp(fn(a), fn(b)); }; } function getLastName(o) { return o.last_nom; } var sortByLastName = sortBy(getLastName); objs.sort(sortByLastName); console.log(objs.map(getLastName));
-(fa < fb) || +(fa > fb)
的简写是错误的。那就是将多条语句压缩成一行代码。使用 if
语句编写的替代方案将更具可读性,同时仍然相当简洁。我认为为了美观而牺牲可读性是错误的。
fa <=> fb
。
const cmp = (a, b) => -(a < b) || +(a > b);
) 想想 ["ä", "a", "c", "b"].sort(cmp)
=> ["a", "b", "c", "ä"]
,其中 ä
被推到最后。相反,您可能应该将比较函数更新为: const cmp = (a, b) => a.localeCompare(b);
=> ["a", "ä", "b", "c"]
干杯并感谢您的回答 ;-)
localeCompare
会删除对数字进行排序的能力,而且速度也会明显变慢。
除了使用自定义比较函数,您还可以使用自定义 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();
这里有很多很好的答案,但我想指出,它们可以非常简单地扩展以实现更复杂的排序。您唯一需要做的就是使用 OR 运算符链接比较函数,如下所示:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
其中 fn1
, fn2
, ... 是返回 [-1,0,1] 的排序函数。这导致“按 fn1 排序”、“按 fn2 排序”,这几乎等于 SQL 中的 ORDER BY。
此解决方案基于计算结果为 first evaluated expression which can be converted to 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 可以带您走很长一段路,而无需外部库或复杂代码。它也非常有效,因为不必进行字符串解析
尝试这个,
UPTO ES5
//Ascending Sort
items.sort(function (a, b) {
return a.value - b.value;
});
//Descending Sort
items.sort(function (a, b) {
return b.value - a.value;
});
IN ES6 & above:
// Ascending sort
items.sort((a, b) => a.value - b.value);
// Descending Sort
items.sort((a, b) => b.value - a.value);
示例用法:
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}
*/
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;
};
};
1, 0, -1
用于排序。即使上面有你的解释,看起来非常好——我还是不太明白。我总是将 -1
视为使用数组长度属性时,即:arr.length = -1
表示未找到该项目。我可能在这里混淆了一些东西,但你能帮我理解为什么使用数字 1, 0, -1
来确定顺序吗?谢谢。
a
和 b
相比,如果 a
大于 b
,则将 1 添加到索引a
放在 b
后面,如果 a
小于 b
,则将 a
减 1 放在 b
前面。如果 a
和 b
相同,则将 0 添加到 a
并将其保留在原处。
我知道这个问题太老了,但我没有看到任何与我类似的实现。
此版本基于 Schwartzian transform idiom。
function sortByAttribute(array, ...attrs) {
// generate an array of predicate-objects contains
// 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);
}
这是一个如何使用它的示例:
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 attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));
为什么不写短代码?
objs.sort((a, b) => a.last_nom > b.last_nom ? 1 : -1)
1, -1, 0
a>b && 1|| -1
等于 a> b ? 1 : -1
,运算符 &&
返回第一个逻辑 false
值,运算符 ||
返回第一个逻辑 true
值。
使用 JavaScript 排序方法
sort
方法可以修改为使用比较函数对数字、字符串甚至对象数组等任何内容进行排序。
比较函数作为可选参数传递给 sort 方法。
此比较函数接受 2 个参数,通常称为 a 和 b。基于这 2 个参数,您可以修改排序方法以根据需要工作。
如果比较函数返回小于 0,则 sort() 方法在比 b 低的索引处对 a 进行排序。简单地说,a 将出现在 b 之前。如果比较函数返回等于 0,则 sort() 方法将元素位置保持原样。如果比较函数返回大于 0,则 sort() 方法在比 b 更大的索引处对 a 进行排序。简单地说,a 将出现在 b 之后。
使用上述概念应用于您的对象,其中 a 将是您的对象属性。
var objs = [ { first_nom: 'Lazslo', last_nom: 'Jamf' }, { first_nom: 'Pig', last_nom: 'Bodine' }, { first_nom: '海盗', last_nom: 'Prentice' } ];函数比较(a,b){如果(a.last_nom>b.last_nom)返回1;如果(a.last_nom < b.last_nom)返回 -1;返回0; } objs.sort(比较); console.log(objs) // 为了更好看,使用 console.table(objs)
排序(更多)复杂的对象数组
由于您可能会遇到像这个数组这样更复杂的数据结构,我将扩展解决方案。
TL;博士
是基于@ege-Özcan 非常可爱的答案的更多可插拔版本。
问题
我遇到了以下问题,无法更改。我也不想暂时压平物体。我也不想使用下划线/lodash,主要是出于性能原因和自己实现它的乐趣。
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
目标
目标是主要按 People.Name.name
排序,其次按 People.Name.surname
障碍
现在,在基本解决方案中,使用括号表示法来计算要动态排序的属性。但是,在这里,我们还必须动态地构造括号符号,因为您会期望像 People['Name.name']
这样的一些符号会起作用 - 但事实并非如此。
另一方面,简单地执行 People['Name']['name']
是静态的,只允许您下降到第 n 级。
解决方案
这里的主要补充是遍历对象树并确定最后一个叶子的值,你必须指定,以及任何中间叶子。
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;
}
}
例子
工作示例 on JSBin
另一种选择:
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));
默认按升序排序。
一个简单的方法:
objs.sort(function(a,b) {
return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});
看到 '.toLowerCase()'
是必要的,以防止在比较字符串时出错。
objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
一个按属性对对象数组进行排序的简单函数
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
}
用法:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc
这是我对此的看法:
order
参数是可选的,默认为“ASC”表示升序。
适用于重音字符并且不区分大小写。
注意:它排序并返回原始数组。
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;
}
片段
function sanitizeToSort(str) { return str .normalize('NFD') // 删除重音符号 .replace(/[\u0300-\u036f]/g,'') // 删除变音符号 .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) => 删除 item.tempProp);返回 arr; } const rockStars = [ { name: "Axl", lastname: "Rose" }, { name: "Elthon", lastname: "John" }, { name: "Paul", lastname: "McCartney" }, { name: "Lou", lastname: "Reed" }, { name: "freddie", // 适用于小写/大写 lastname: "mercury" }, { name: "Ámy", // 适用于重音字符 lastname: "酒屋”} ]; sortByProperty(rockStars,"name"); console.log("按名称 AZ 排序:"); rockStars.forEach((item) => console.log(item.name + " " + item.lastname)); sortByProperty(rockStars,"姓氏","DESC"); console.log("\n按姓 ZA 排序:"); rockStars.forEach((item) => console.log(item.lastname + ", " + item.name));
警告!不建议使用此解决方案,因为它不会导致排序数组。它留在这里供将来参考,因为这个想法并不罕见。
objs.sort(function(a,b){return b.last_nom>a.last_nom})
将 Ege 的动态解决方案与 Vinay 的想法相结合,您将得到一个很好的稳健解决方案:
Array.prototype.sortBy = function() { function _sortByAttr(attr) { var sortOrder = 1; if (attr[0] == "-") { sortOrder = -1; attr = attr.substr(1); } 返回函数(a,b){ var 结果 =(a[attr] < b[attr])? -1 : (a[attr] > b[attr]) ? 1:0;返回结果 * 排序顺序; } } function _getSortFunc() { if (arguments.length == 0) { throw "Array.sortBy() 不允许零长度参数"; } var args = 参数; return function(a, b) { for (var result = 0, i = 0; result == 0 && i < args.length; i++) { result = _sortByAttr(args[i])(a, b); } 返回结果; } } 返回 this.sort(_getSortFunc.apply(null, arguments)); } 用法: // 打印对象的实用程序 Array.prototype.print = function(title) { console.log("****************************** ***********************************************"); console.log("****" + 标题); console.log("*************************************************** ******************************"); for (var i = 0; i < this.length; i++) { console.log("Name: " + this[i].FirstName, this[i].LastName, "Age:" + this[i].Age ); } } // 设置示例数据 var arrObj = [{ FirstName: "Zach", LastName: "Emergency", Age: 35 }, { FirstName: "Nancy", LastName: "Nurse", Age: 27 }, { FirstName: “埃塞尔”,姓:“紧急”,年龄:42 },{ 名字:“尼娜”,姓:“护士”,年龄:48 },{ 名字:“安东尼”,姓:“紧急”,年龄:44 } , { FirstName: "Nina", LastName: "Nurse", Age: 32 }, { FirstName: "Ed", LastName: "Emergency", Age: 28 }, { FirstName: "Peter", LastName: "Physician",年龄:58 },{ 名字:“Al”,姓氏:“紧急”,年龄:51 },{ 名字:“Ruth”,姓氏:“注册”,年龄:62 },{ 名字:“Ed”,姓氏: “紧急情况”,年龄:38 },{名字:“Tammy”,姓氏:“Triage”,年龄:29 },{名字:“Alan”,姓氏:“紧急情况”,年龄:60 },{名字:“Nina” ", 姓: "护士", 年龄: 54 } ]; //单元测试 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");
Ege Özcan 代码的附加 desc 参数
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;
}
}
给定原始示例:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
按多个字段排序:
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;
});
笔记
a.localeCompare(b) 得到普遍支持,如果 ab 分别返回 -1,0,1。
||在最后一行中,last_nom 优先于 first_nom。
减法适用于数字字段: var age_order = left.age - right.age;
取反顺序,返回 -last_nom_order || -first_nom_order || -年龄顺序;
function compare(propName) {
return function(a,b) {
if (a[propName] < b[propName])
return -1;
if (a[propName] > b[propName])
return 1;
return 0;
};
}
objs.sort(compare("last_nom"));
使用 Ramda,
npm 安装 ramda
import R from 'ramda'
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)
return a.last_nom.localeCompare(b.last_nom)
也可以。return a.value - b.value;
(ASC)charCodeAt
将字符串转换为数字,然后使用上面的数字内联以获得更简洁的一行:objs.sort((a,b) => a.last_nom.charCodeAt(0) - b.last_nom.charCodeAt(0));
。这避免了丑陋的嵌套三元组。