提问人:Tyrone Slothrop 提问时间:7/15/2009 最后编辑:AdamTyrone Slothrop 更新时间:9/20/2023 访问量:3201866
按字符串属性值对对象数组进行排序
Sort array of objects by string property value
问:
我有一个 JavaScript 对象数组:
var objs = [
{ first_nom: 'Laszlo', 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
评论
return a.last_nom.localeCompare(b.last_nom)
也会起作用。
return a.value - b.value;
charCodeAt
objs.sort((a,b) => a.last_nom.charCodeAt(0) - b.last_nom.charCodeAt(0));
如果您有重复的姓氏,您可以按名字对它们进行排序 -
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
1, 0, -1
除了使用自定义比较函数,您还可以使用自定义方法(由默认比较函数调用)创建对象类型: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();
您还可以创建一个动态排序函数,该函数按您传递的值对对象进行排序:
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"));
实际上,这已经回答了这个问题。下面的部分是因为很多人联系了我,抱怨它不适用于多个参数。
多个参数
您可以使用下面的函数生成具有多个排序参数的排序函数。
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");
评论
使用下划线.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');
评论
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'] );
使用原型继承简单快速地解决此问题:
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"}]
更新:不再修改原始数组。
评论
.slice(0)
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;
}
}
评论
将 Ege 的动态解决方案与 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));
}
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 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");
评论
您可能需要将它们转换为小写形式,以防止混淆。
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
})
用法示例:
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
a
b
a
b
a
b
a
b
a
根据您的示例,您需要按两个字段(姓氏、名字)而不是一个字段进行排序。您可以使用 Alasql 库在一行中进行此排序:
var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);
在 JSFiddle 中试试这个例子。
使用 xPrototype 的 sortBy:
var o = [
{ Name: 'Lazslo', LastName: 'Jamf' },
{ Name: 'Pig', LastName: 'Bodine' },
{ Name: 'Pirate', LastName: 'Prentice' },
{ Name: 'Pag', LastName: 'Bodine' }
];
// Original
o.each(function (a, b) { console.log(a, b); });
/*
0 Object {Name: "Lazslo", LastName: "Jamf"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Pirate", LastName: "Prentice"}
3 Object {Name: "Pag", LastName: "Bodine"}
*/
// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pag", LastName: "Bodine"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Lazslo", LastName: "Jamf"}
3 Object {Name: "Pirate", LastName: "Prentice"}
*/
// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pag", LastName: "Bodine"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Lazslo", LastName: "Jamf"}
3 Object {Name: "Pirate", LastName: "Prentice"}
*/
// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pirate", LastName: "Prentice"}
1 Object {Name: "Lazslo", LastName: "Jamf"}
2 Object {Name: "Pig", LastName: "Bodine"}
3 Object {Name: "Pag", LastName: "Bodine"}
*/
// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pirate", LastName: "Prentice"}
1 Object {Name: "Lazslo", LastName: "Jamf"}
2 Object {Name: "Pag", LastName: "Bodine"}
3 Object {Name: "Pig", LastName: "Bodine"}
*/
我只是增强了 Ege Özcan 的动态排序功能,使其深入到对象内部。
如果数据如下所示:
obj = [
{
a: { a: 1, b: 2, c: 3 },
b: { a: 4, b: 5, c: 6 }
},
{
a: { a: 3, b: 2, c: 1 },
b: { a: 6, b: 5, c: 4 }
}];
如果你想对一个属性进行排序,我认为我的增强功能很有帮助。我向如下所示的对象添加新功能:
Object.defineProperty(Object.prototype, 'deepVal', {
enumerable: false,
writable: true,
value: function (propertyChain) {
var levels = propertyChain.split('.');
parent = this;
for (var i = 0; i < levels.length; i++) {
if (!parent[levels[i]])
return undefined;
parent = parent[levels[i]];
}
return parent;
}
});
并更改了 _dynamicSort 的返回函数:
return function (a, b) {
var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
return result * sortOrder;
}
现在你可以这样按a.a.排序:
obj.sortBy('a.a');
请参阅 JSFiddle 中的完整脚本。
排序 (更多) 复杂的对象数组
由于您可能会遇到像这个数组这样的更复杂的数据结构,因此我将扩展解决方案。
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']
另一方面,简单地做是静态的,只允许你进入第 n 级。People['Name']['name']
溶液
这里的主要新增功能是沿着对象树走下去,并确定您必须指定的最后一个叶子的值,以及任何中间叶子。
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;
}
}
例
JSBin 上的工作示例
评论
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"));
评论
这是一个简单的问题。我不知道为什么人们会有如此复杂的解决方案。
一个简单的排序函数(基于快速排序算法):
function sortObjectsArray(objectsArray, sortKey)
{
// Quick Sort:
var retVal;
if (1 < objectsArray.length)
{
var pivotIndex = Math.floor((objectsArray.length - 1) / 2); // Middle index
var pivotItem = objectsArray[pivotIndex]; // Value in the middle index
var less = [], more = [];
objectsArray.splice(pivotIndex, 1); // Remove the item in the pivot position
objectsArray.forEach(function(value, index, array)
{
value[sortKey] <= pivotItem[sortKey] ? // Compare the 'sortKey' proiperty
less.push(value) :
more.push(value) ;
});
retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
}
else
{
retVal = objectsArray;
}
return retVal;
}
使用示例:
var myArr =
[
{ val: 'x', idx: 3 },
{ val: 'y', idx: 2 },
{ val: 'z', idx: 5 },
];
myArr = sortObjectsArray(myArr, 'idx');
评论
一个简单的方法:
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() );
在 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
>
警告!
不建议使用此解决方案,因为它不会导致排序数组。它被留在这里以备将来参考,因为这个想法并不罕见。
objs.sort(function(a,b){return b.last_nom>a.last_nom})
评论
我遇到了对对象数组进行排序的问题,并更改了值的优先级。基本上,我想按年龄对一系列民族进行排序,然后按姓氏 - 或者只是按姓氏,名字。
我认为与其他答案相比,这是最简单的解决方案。
它是通过调用 来使用的。sortPeoples(['array', 'of', 'properties'], reverse=false)
/////////////////////// Example array of peoples ///////////////////////
var peoples = [
{name: "Zach", surname: "Emergency", age: 1},
{name: "Nancy", surname: "Nurse", age: 1},
{name: "Ethel", surname: "Emergency", age: 1},
{name: "Nina", surname: "Nurse", age: 42},
{name: "Anthony", surname: "Emergency", age: 42},
{name: "Nina", surname: "Nurse", age: 32},
{name: "Ed", surname: "Emergency", age: 28},
{name: "Peter", surname: "Physician", age: 58},
{name: "Al", surname: "Emergency", age: 58},
{name: "Ruth", surname: "Registration", age: 62},
{name: "Ed", surname: "Emergency", age: 38},
{name: "Tammy", surname: "Triage", age: 29},
{name: "Alan", surname: "Emergency", age: 60},
{name: "Nina", surname: "Nurse", age: 58}
];
//////////////////////// Sorting function /////////////////////
function sortPeoples(propertyArr, reverse) {
function compare(a, b) {
var i = 0;
while (propertyArr[i]) {
if (a[propertyArr[i]] < b[propertyArr[i]])
return -1;
if (a[propertyArr[i]] > b[propertyArr[i]])
return 1;
i++;
}
return 0;
}
peoples.sort(compare);
if (reverse) {
peoples.reverse();
}
};
//////////////// End of sorting method ///////////////
function printPeoples() {
$('#output').html('');
peoples.forEach(function(person) {
$('#output').append(person.surname + " " + person.name + " " + person.age + "<br>");
})
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<html>
<body>
<button onclick="sortPeoples(['surname']); printPeoples()">sort by ONLY by surname ASC results in mess with same name cases</button><br>
<button onclick="sortPeoples(['surname', 'name'], true); printPeoples()">sort by surname then name DESC</button><br>
<button onclick="sortPeoples(['age']); printPeoples()">sort by AGE ASC. Same issue as in first case</button><br>
<button onclick="sortPeoples(['age', 'surname']); printPeoples()">sort by AGE and Surname ASC. Adding second field fixed it.</button><br>
<div id="output"></div>
</body>
</html>
评论
head
html
这里有很多很好的答案,但我想指出的是,它们可以非常简单地扩展以实现更复杂的排序。您唯一需要做的就是使用 OR 运算符来链接比较函数,如下所示:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
哪里。。。是返回 [-1,0,1] 的排序函数。这导致“按 fn1 排序”和“按 fn2 排序”,这几乎等于 SQL 中的 ORDER BY。fn1
fn2
此解决方案基于运算符的行为,该行为的计算结果为第一个计算的表达式,该表达式可以转换为 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 可以在没有外部库或复杂代码的情况下走很长的路。它也非常有效,因为不需要进行字符串解析。
还有一个选择:
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));
默认情况下,它按升序排序。
评论
对对象数组进行排序
// Data
var booksArray = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
// Property to sort by
var args = "last_nom";
// Function to sort the data by the given property
function sortByProperty(property) {
return function (a, b) {
var sortStatus = 0,
aProp = a[property].toLowerCase(),
bProp = b[property].toLowerCase();
if (aProp < bProp) {
sortStatus = -1;
} else if (aProp > bProp) {
sortStatus = 1;
}
return sortStatus;
};
}
// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));
console.log("sortedArray: " + JSON.stringify(sortedArray) );
控制台日志输出:
"sortedArray:
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"
根据此来源改编:代码片段:如何按属性对 JSON 对象数组进行排序
这将按按字母数字顺序传递给它的属性对两级嵌套数组进行排序。
function sortArrayObjectsByPropAlphaNum(property) {
return function (a,b) {
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
var aA = a[property].replace(reA, '');
var bA = b[property].replace(reA, '');
if(aA === bA) {
var aN = parseInt(a[property].replace(reN, ''), 10);
var bN = parseInt(b[property].replace(reN, ''), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return a[property] > b[property] ? 1 : -1;
}
};
}
用法:
objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));
我没有看到任何与我类似的实现。此版本基于 Schwartzian 变换习语。
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);
}
下面是一个如何使用它的示例:
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'));
因此,这里有一种排序算法,它可以以任何顺序对任何类型的对象进行排序,而不受数据类型比较(即数字、字符串等)的限制:
function smoothSort(items,prop,reverse) {
var length = items.length;
for (var i = (length - 1); i >= 0; i--) {
//Number of passes
for (var j = (length - i); j > 0; j--) {
//Compare the adjacent positions
if(reverse){
if (items[j][prop] > items[j - 1][prop]) {
//Swap the numbers
var tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
if(!reverse){
if (items[j][prop] < items[j - 1][prop]) {
//Swap the numbers
var tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
}
}
return items;
}
第一个参数项是对象数组,
prop 是要排序的对象的键,
reverse 是一个布尔参数,如果为 true,则返回升序,如果为 false,则返回降序。
使用 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)
评论
我将为您提供一个实现选择排序算法的解决方案。它简单而有效。
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
function selection_Sort(num) {
//console.log(num);
var temp, index;
for (var i = 0; i <= num.length - 1; i++) {
index = i;
for (var j = i + 1; j <= num.length - 1; j++) {
// You can use first_nom/last_nom, any way you choose to sort
if (num[j].last_nom < num[index].last_nom) {
index = j;
}
}
// Below is the swapping part
temp = num[i].last_nom;
num[i].last_nom = num[index].last_nom;
num[index].last_nom = temp;
};
console.log(num);
return num;
}
selection_Sort(objs);
最好不要为每个简单的逻辑添加框架,但依靠经过充分测试的实用程序框架可以加快开发速度并减少错误数量。
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 速记来指定应匹配的属性的路径。我们将按嵌套的 age 属性对用户对象进行排序。是的,它允许嵌套属性匹配!user.age
const sortedObjs = _.sortBy(users, ['user.age']);
想要逆转吗?没关系。使用 _.reverse。
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));
想用链子把两者结合起来吗?
const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();
或者你什么时候更喜欢流动而不是链?
const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users);
不正确的旧答案:
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()
给定原始示例:
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)
普遍支持,如果 ,则返回 -1,0,1。a<b
a==b
a>b
||
在最后一行中,优先于 .last_nom
first_nom
- 减法适用于数值字段:
var age_order = left.age - right.age;
- 否定到反序,
return -last_nom_order || -first_nom_order || -age_order;
使用 Lodash 或 Underscore.js,这是小菜一碟:
const sortedList = _.orderBy(objs, [last_nom], [asc]); // Ascending or descending
一个简单的函数,它按属性对对象数组进行排序:
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
评论
方式1:
可以使用下划线.js。首先导入下划线。
import * as _ from 'underscore';
let SortedObjs = _.sortBy(objs, 'last_nom');
方式2:使用比较功能。
function compare(first, second) {
if (first.last_nom < second.last_nom)
return -1;
if (first.last_nom > second.last_nom)
return 1;
return 0;
}
objs.sort(compare);
截至 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
它对我有用。在这里,它将保持未定义到最后。
function sort(items, property, direction) {
function compare(a, b) {
if(!a[property] && !b[property]) {
return 0;
} else if(a[property] && !b[property]) {
return -1;
} else if(!a[property] && b[property]) {
return 1;
} else {
const value1 = a[property].toString().toUpperCase(); // ignore upper and lowercase
const value2 = b[property].toString().toUpperCase(); // ignore upper and lowercase
if (value1 < value2) {
return direction === 0 ? -1 : 1;
} else if (value1 > value2) {
return direction === 0 ? 1 : -1;
} else {
return 0;
}
}
}
return items.sort(compare);
}
var items = [
{ name: 'Edward', value: 21 },
{ name: 'Sharpe', value: 37 },
{ name: 'And', value: 45 },
{ name: 'The', value: -12 },
{ name: undefined, value: -12 },
{ name: 'Magnetic', value: 13 },
{ name: 'Zeros', value: 37 }
];
console.log('Ascending Order:- ');
console.log(sort(items, 'name', 0));
console.log('Decending Order:- ');
console.log(sort(items, 'name', 1));
我还没有看到这种特定方法的建议,所以这里有一个我喜欢使用的简洁比较方法,它适用于这两种类型:string
number
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));
解释sortBy()
sortBy()
接受一个,它从对象中选择一个值进行比较,并返回一个可以传递给 Array.prototype.sort()
的函数。在此示例中,我们将比较 .每当我们收到两个对象时,例如fn
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
我们可以将比较函数扩展为 。由于逻辑 OR (||
) 在 JavaScript 中的工作方式,等价于(a, b) => cmp(a.last_nom, b.last_nom)
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;
顺便说一句,这在其他语言中被称为三向比较“宇宙飞船”(<=>
)运算符。
最后,下面是不使用箭头函数的 ES5 兼容语法:
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));
评论
-(fa < fb) || +(fa > fb)
if
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
你可以使用 最简单的方法:Lodash
(https://lodash.com/docs/4.17.10#orderBy)
此方法与此方法类似,只是它允许指定要排序的迭代的排序顺序。如果未指定 orders,则所有值均按升序排序。否则,请指定“desc”的降序或“asc”的升序排序顺序。_.sortBy
参数
集合 (Array|Object):要循环访问的集合。 [迭代=[_.identity]](数组[]|函数[]|Object[]|string[]):要排序的迭代。 [订单](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']);
评论
如果您有嵌套对象
const objs = [{
first_nom: 'Lazslo',
last_nom: 'Jamf',
moreDetails: {
age: 20
}
}, {
first_nom: 'Pig',
last_nom: 'Bodine',
moreDetails: {
age: 21
}
}, {
first_nom: 'Pirate',
last_nom: 'Prentice',
moreDetails: {
age: 22
}
}];
nestedSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
const a = prop2 ? e1[prop1][prop2] : e1[prop1],
b = prop2 ? e2[prop1][prop2] : e2[prop1],
sortOrder = direction === "asc" ? 1 : -1
return (a < b) ? -sortOrder : (a > b) ? sortOrder : 0;
}
并称它为
objs.sort(nestedSort("last_nom"));
objs.sort(nestedSort("last_nom", null, "desc"));
objs.sort(nestedSort("moreDetails", "age"));
objs.sort(nestedSort("moreDetails", "age", "desc"));
在 TypeScript 中编程时也可以制作动态排序函数,但在这种情况下类型变得更加棘手。
function sortByKey<O>(key: keyof O, decending: boolean = false): (a: O, b: O) => number {
const order = decending ? -1 : 1;
return (a, b): number => {
const valA = a[key];
const valB = b[key];
if (valA < valB) {
return -order;
} else if (valA > valB) {
return order;
} else {
return 0;
}
}
}
这可以在 TypeScript 中使用,如下所示:
const test = [
{
id: 0,
},
{
id: 2,
}
]
test.sort(sortByKey('id')) // OK
test.sort(sortByKey('id1')) // ERROR
test.sort(sortByKey('')) // ERROR
此排序函数可用于所有对象排序:
- 对象
- deep对象
- 数值数组
您还可以通过将 1、-1 作为参数传递来执行升序或降序排序。
Object.defineProperty(Object.prototype, 'deepVal', {
enumerable: false,
writable: true,
value: function (propertyChain) {
var levels = propertyChain.split('.');
parent = this;
for (var i = 0; i < levels.length; i++) {
if (!parent[levels[i]])
return undefined;
parent = parent[levels[i]];
}
return parent;
}
});
function dynamicSortAll(property, sortOrders=1) {
/** The default sorting will be ascending order. If
you need descending order sorting you have to
pass -1 as the parameter **/
var sortOrder = sortOrders;
return function (a, b) {
var result = (property? ((a.deepVal(property) > b.deepVal(property)) ? 1 : (a.deepVal(property) < b.deepVal(property)) ? -1 : 0) : ((a > b) ? 1 : (a < b) ? -1 : 0))
return result * sortOrder;
}
}
deepObj = [
{
a: { a: 1, b: 2, c: 3 },
b: { a: 4, b: 5, c: 6 }
},
{
a: { a: 3, b: 2, c: 1 },
b: { a: 6, b: 5, c: 4 }
}];
let deepobjResult = deepObj.sort(dynamicSortAll('a.a', 1))
console.log('deepobjResult: ' + JSON.stringify(deepobjResult))
var obj = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
let objResult = obj.sort(dynamicSortAll('last_nom', 1))
console.log('objResult: ' + JSON.stringify(objResult))
var numericObj = [1, 2, 3, 4, 5, 6]
let numResult = numericObj.sort(dynamicSortAll(null, -1))
console.log('numResult: ' + JSON.stringify(numResult))
let stringSortResult = 'helloworld'.split('').sort(dynamicSortAll(null, 1))
console.log('stringSortResult: ' + JSON.stringify(stringSortResult))
let uniqueStringOrger=[...new Set(stringSortResult)];
console.log('uniqueStringOrger: ' + JSON.stringify(uniqueStringOrger))
下面是一个函数,可用于按多个对象对列表进行排序,如果第一个对象相等,则第二个顺序将用作回退。如果可能,也应忽略空值以回退顺序。
function sortObjects(list, orderBy){
list.sort(function(a, b){
let byIndex = 0;
let order = orderBy[byIndex];
while(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
byIndex++;
if(byIndex >= orderBy.length){break;}
order = orderBy[byIndex];
}
if(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
return false;
}
if(order.desc){
return a[order.by] < b[order.by];
}
return a[order.by] > b[order.by];
});
return list;
}
用法:
var objs = [
{a: 10, b: 20, c: 30},
{a: 30, b: 10, c: 20},
{a: 20, b: 10, c: 30},
];
sortObjectList(objs, [{by: 'a'}]);
[
{a: 10, b: 20, c: 30},
{a: 20, b: 10, c: 30},
{a: 30, b: 10, c: 20},
]
sortObjectList(objs, [{by: 'a', desc: true}]);
[
{a: 30, b: 10, c: 20},
{a: 20, b: 10, c: 30},
{a: 10, b: 20, c: 30},
]
sortObjectList(objs, [{by: 'b', desc: true}, {by: 'c'}]);
[
{a: 10, b: 20, c: 30},
{a: 30, b: 10, c: 20},
{a: 20, b: 10, c: 30},
]
另一个例子:
var objs = [
{a: 5, b: 5},
{a: 10, b: 15},
{a: 15, b: 25},
{b: 10},
{b: 20},
{a: 10, b: 30},
{a: 10, b: 12},
];
sortObjectList(objs, [{by: 'a'}, {by: 'b'}]);
[
{a: 5, b: 5},
{b: 10},
{a: 10, b: 12},
{a: 10, b: 15},
{b: 20},
{a: 10, b: 30},
{a: 15, b: 25},
]
这是我对此的看法:
该参数是可选的,默认为“ASC”,表示升序。order
它适用于重音字符,并且不区分大小写。
注意:它对原始数组进行排序并返回。
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') // 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));
评论
试试这个:
最高 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;
});
在 ES6 及更高版本中
// Ascending sort
items.sort((a, b) => a.value - b.value);
// Descending sort
items.sort((a, b) => b.value - a.value);
评论
您可以使用可重用的排序函数。
Array.prototype.order = function (prop, methods = {}) {
if (prop?.constructor == Object) {
methods = prop;
prop = null;
}
const [orderType_a, orderType_b] = methods.reverse ? [1, -1] : [-1, 1];
const $ = x => prop
? methods.insensitive
? String(x[prop]).toLowerCase()
: x[prop]
: methods.insensitive
? String(x).toLowerCase()
: x;
const fn = (a, b) => $(a) < $(b) ? orderType_a : $(b) < $(a) ? orderType_b : 0;
return this.sort(fn);
};
它可用于对数组和数组中的对象进行排序。
let items = [{ x: "Z" }, 3, "1", "0", 2, { x: "a" }, { x: 0 }];
items
.order("x", { insensitive: 1 })
// [ { x: 0 }, { x: 'a' }, 3, '1', '0', 2, { x: 'Z' } ]
.order({ reverse: 1 })
// [ { x: 0 }, { x: 'a' }, 3, 2, { x: 'Z' }, '1', '0' ]
.sort(x => typeof x == "string" || typeof x == "number" ? -1 : 0)
// [ '0', '1', 2, 3, { x: 0 }, { x: 'a' }, { x: 'Z' } ]
第一个(可选)>对数组中包含的对象进行排序。
第二是方法 > { reverse: any, insensitive: any }
深
基于这个优秀的教程,我想发展 Vlad Bezden 的答案,并解释为什么 localeCompare
比标准比较方法更好,比如 .让我们运行这个例子:strA > strB
console.log( 'Österreich' > 'Zealand' ); // We expect false
console.log( 'a' > 'Z' ); // We expect false
原因是在 JavaScript 中,所有字符串都使用 UTF-16 和
let str = '';
// Order of characters in JavaScript
for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i); // Code to character
}
console.log(str);
大写字母先走(有小代码),然后是小写字母,然后是字符(之后)。这就是我们在第一个代码片段中得到 true 的原因 - 因为运算符比较字符代码。Ö
z
>
正如你所看到的,比较不同语言的字符是一项艰巨的任务 - 但幸运的是,现代浏览器支持国际化标准ECMA-402。因此,在 JavaScript 中,我们有 which 来完成这项工作(means is less ; 1 means 相反; 0 means equal)strA.localeCompare(strB)
-1
strA
strB
console.log( 'Österreich'.localeCompare('Zealand') ); // We expect -1
console.log( 'a'.localeCompare('Z') ); // We expect -1
我想补充一点,它支持两个参数:语言和附加规则:localeCompare
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' },
{ first_nom: 'Test', last_nom: 'jamf' }
];
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom,'en',{sensitivity:'case'}))
console.log(objs);
// in '>' comparison 'Jamf' will NOT be next to 'jamf'
简单回答:
objs.sort((a,b)=>a.last_nom.localeCompare(b.last_nom))
详:
今天很简单,你可以将字符串与 .正如 Mozilla Doc 所说:localeCompare
该方法返回一个数字,指示 引用字符串为 、 或 或 。
localeCompare()
before
after
is the same as the given string in sort order
//example1:
console.log("aaa".localeCompare("aab")); //-1
console.log("aaa".localeCompare("aaa")); //0
console.log("aab".localeCompare("aaa")); //1
//example2:
const a = 'réservé'; // with accents, lowercase
const b = 'RESERVE'; // no accents, uppercase
console.log(a.localeCompare(b));
// expected output: 1
console.log(a.localeCompare(b, 'en', { sensitivity: 'base' }));
// expected output: 0
有关详细信息,请参阅 Mozilla 文档localeCompare
:
const objectSorter = (p) => (a, b) => ((a, b) => a>b ? 1 : a<b ? -1 : 0)(a[p], b[p]);
objs.sort(objectSorter('first_nom'));
使用 JavaScript 方法sort
可以使用比较函数修改 sort
方法,以对数字、字符串甚至对象数组等任何内容进行排序。
compare 函数作为可选参数传递给 sort 方法。
此比较函数接受 2 个参数,通常称为 a 和 b。基于这 2 个参数,您可以修改排序方法以根据需要工作。
- 如果 compare 函数返回的分数小于 0,则该方法将 a 排序为低于 b 的索引。简单地说,a 将出现在 b 之前。
sort()
- 如果 compare 函数返回等于 0,则该方法将元素位置保持原样。
sort()
- 如果 compare 函数返回大于 0,则该方法在索引处对 a 进行排序,索引大于 b。只是 a 会在 b 之后出现。
sort()
使用上述概念应用于对象,其中 a 将是对象属性。
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)

我一直在各种项目中使用此实用程序,效果很好。它也是非常模块化的:
- 传递要排序的键的名称
- 选择排序是升序还是降序
sortArrayOfObjsByKeyUtil.js
// Sort array of objects by key
// ------------------------------------------------------------
const sortArrayOfObjsByKey = (array, key, ascdesc) =>
array.sort((a, b) => {
const x = a[key];
const y = b[key];
if (ascdesc === 'asc') {
return x < y ? -1 : x > y ? 1 : 0;
}
if (ascdesc === 'desc') {
return x > y ? -1 : x < y ? 1 : 0;
}
return null;
});
sortArrayOfObjsByKeyUtil.test.js
import sortArrayOfObjsByKey from './sortArrayOfObjsByKeyUtil';
const unsortedArray = [
{
_id: '3df55221-ce5c-4147-8e14-32effede6133',
title: 'Netlife Design',
address: {
PostalAddress: {
streetAddress: 'Youngstorget 3',
addressLocality: 'Oslo',
addressRegion: null,
postalCode: '0181',
addressCountry: 'Norway',
},
},
geopoint: { lat: 59.914322, lng: 10.749272 },
},
{
_id: 'cd00459f-3755-49f1-8847-66591ef935b2',
title: 'Home',
address: {
PostalAddress: {
streetAddress: 'Stockfleths gate 58A',
addressLocality: 'Oslo',
addressRegion: null,
postalCode: '0461',
addressCountry: 'Norway',
},
},
geopoint: { lat: 59.937316, lng: 10.751862 },
},
];
const sortedArray = [
{
_id: 'cd00459f-3755-49f1-8847-66591ef935b2',
title: 'Home',
address: {
PostalAddress: {
streetAddress: 'Stockfleths gate 58A',
addressLocality: 'Oslo',
addressRegion: null,
postalCode: '0461',
addressCountry: 'Norway',
},
},
geopoint: { lat: 59.937316, lng: 10.751862 },
},
{
_id: '3df55221-ce5c-4147-8e14-32effede6133',
title: 'Netlife Design',
address: {
PostalAddress: {
streetAddress: 'Youngstorget 3',
addressLocality: 'Oslo',
addressRegion: null,
postalCode: '0181',
addressCountry: 'Norway',
},
},
geopoint: { lat: 59.914322, lng: 10.749272 },
},
];
describe('sortArrayOfObjsByKey', () => {
it(`sort array by 'title' key, ascending`, () => {
const testInput = sortArrayOfObjsByKey(unsortedArray, 'title', 'asc');
const testOutput = sortedArray;
expect(testInput).toEqual(testOutput);
});
});
编写短代码:
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
试试这个方法:
let objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
const compareBylastNom = (a, b) => {
// Converting to uppercase to have case-insensitive comparison
const name1 = a.last_nom.toUpperCase();
const name2 = b.last_nom.toUpperCase();
let comparison = 0;
if (name1 > name2) {
comparison = 1;
} else if (name1 < name2) {
comparison = -1;
}
return comparison;
}
console.log(objs.sort(compareBylastNom));
区分大小写
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: 'Pirate', last_nom: 'Prentice' }
];
// Define a couple of sorting callback functions, one with hardcoded sort key and the other with an argument sort key
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("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);
评论
-1
1
1 : -1
-1 : 1
(a, b) to (b, a)
1
-1
我知道已经有很多答案,包括那些带有 localeCompare 的答案,但如果您出于某种原因不想/不能使用 localeCompare,我建议您使用此解决方案而不是三元运算符解决方案:
objects.sort((a, b) => (a.name > b.name) - (a.name < b.name));
有人可能会说这段代码在做什么并不明显,但在我看来,三元运算符更糟。如果一个三元运算符的可读性足够高,那么两个三元运算符一个嵌入到另一个运算符中——真的很难读,而且很丑陋。只有两个比较运算符和一个减号运算符的单行代码非常易于阅读,因此易于推理。
使用 Intl.Collator
对对象进行排序,以备特定情况下进行自然字符串排序(即 )。["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);
注意:构造函数参数 for 表示区域设置,可以是显式的 ISO 639-1 语言代码,例如 ,也可以是系统默认区域设置,当 .undefined
Intl.Collator
en
undefined
评论
let propName = 'last_nom';
let sorted_obj = objs.sort((a,b) => {
if(a[propName] > b[propName]) {
return 1;
}
if (a[propName] < b[propName]) {
return -1;
}
return 0;
}
//This works because the js built-in sort function allows us to define our
//own way of sorting, this funny looking function is simply telling `sort` how to
//determine what is larger.
//We can use `if(a[propName] > b[propName])` because string comparison is already built into JS
//if you try console.log('a' > 'z' ? 'a' : 'z')
//the output will be 'z' as 'a' is not greater than 'z'
//The return values 0,-1,1 are how we tell JS what to sort on. We're sorting on the last_nom property of the object.
//When sorting a list it comes down to comparing two items and how to determine which one of them is "larger".
//We need a way to tell JS how to determine which one is larger.
//The sort defining function will use the case that returns a 1 to mean that a > b
//and the case that returns -1 to mean that a < b
评论
last_nom
Intl.Collator
对象的排序顺序相互比较
:如果 string1 位于
string2
之前,则为负值;
如果 string1
位于 string2
之后,则为正值;如果它们被认为是相等的,则为 0。
我会这样做:
[...objs].sort((a, b) => a.last_nom.localeCompare(b.last_nom))
我喜欢下面。
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
objs.sort(function(a, b) {
const nameA = a.name.toUpperCase(); // ignore upper and lowercase
const nameB = b.name.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
console.log(arr);
var objs = [
{ firstName: 'A', lastName: 'Mark' }, // b
{ firstName: 'E', lastName: 'askavy' }, // a
{ firstName: 'C', lastName: 'peter' }
];
objs.sort((a,b) => {
return a.firstName.localeCompare(b.firstName) // Sort Ascending
})
objs.sort((a,b) => {
return b.firstName.localeCompare(a.firstName) // Sort Decending
})
console.log(objs)
您还可以添加一个通用函数,用于按升序或降序对字符串和数字进行排序,例如:
function sortArray({ data, key, sortingOrder }) {
return data.sort((a, b) => {
const firstValue = typeof a[key] === 'string' ? a[key]?.toLowerCase() : a[key];
const secondValue = typeof b[key] === 'string' ? b[key]?.toLowerCase() : b[key];
if (firstValue < secondValue) {
return sortingOrder === SORT_ORDER.ASC ? -1 : 1;
}
if (firstValue > secondValue) {
return sortingOrder === SORT_ORDER.ASC ? 1 : -1;
}
return 0;
});
}
const SORT_ORDER={
DES: 'Z-A',
ASC: 'A-Z'
};
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Zwalle' },
{ first_nom: 'Pig', last_nom: 'Podine' },
{ first_nom: 'Pirate', last_nom: 'Antun' }
];
const sortedArray = sortArray({
data: objs,
key: 'last_nom',
sortingOrder: SORT_ORDER.ASC
});
console.log('sorted array', sortedArray);
function compareProperty({ key, direction }) {
return function (a, b) {
const ap = a[key] || ''
const bp = b[key] || ''
return (direction === "desc" ? -1 : 1) * ((typeof ap === "string" && typeof bp === "string") ? ap.localeCompare(bp) : ap - bp)
}
}
使用 null、未定义的键。数字、日期、字符串、带有变音符号的字符按预期排序。
用:
const sort = {
key: "name",
direction: "asc"
}
results.toSorted(compareProperty(sort))
评论