如何按键"multi sort" JavaScript 中的对象数组



我正在尝试"增强";我的排序函数,用于接受多个条件,从而对我的对象数组进行多次排序。

如果这是一个简单的问题,或者如果我犯了' newbie';错误,但我是一个学习JS基础的前端开发人员,我正在努力学习排序函数是如何工作的。

下面是我的代码:

const arrayOfObjects = [
{
name: 'John',
age: 30,
city: 'New York',
details: {
occupation: 'developer',
}
},
{
name: 'Jane',
age: 25,
city: 'Paris',
details : {
occupation: 'designer',
}
}
];
// This is my main sorting function that I'd like to use for "multi sorting" an array of objects
function sortByKey(criteria) {

return (a, b) => {
let comparison = 0;
criteria.forEach(criterion => {
const varA = (typeof resolvePath(criterion.key, a) === 'string')
? resolvePath(criterion.key, a).toUpperCase() : resolvePath(criterion.key, a);
const varB = (typeof resolvePath(criterion.key, b) === 'string')
? resolvePath(criterion.key, b).toUpperCase() : resolvePath(criterion.key, b);
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
if(criterion.order === 'desc') {
comparison = (comparison * -1)
} 
});

return comparison;
};
}
// This function is used to resolve the path of a key in an object
function resolvePath(path, obj) {
return path.split('.').reduce(function(prev, curr) {
return prev ? prev[curr] : null
}, obj || self)
}

这个的用法是:

// MAIN USAGE
console.log( arrayOfObjects.sort(sortByKey([ { key: 'age' } ])) )
console.log( arrayOfObjects.sort(sortByKey([ { key: 'details.occupation', order: 'desc' } ])) )

但是我想用它:

console.log( arrayOfObjects.sort(sortByKey([ { key: 'details.occupation' }, { key: 'age', order: 'desc' ])) )

这是因为我想让用户能够按照某种顺序对我的数组进行多重排序,比如"年龄第一,姓名第二,等等">

谢谢你的帮助,祝你有个愉快的一天!

创建一个函数,该函数返回每个标准的比较器值。循环遍历数组并调用比较函数,直到找到非零值。当compareByKey返回1-1时,find将停止查找

const sortByKey = (criteria) => (a, b) => {
let returnValue = 0;
criteria.find(c => returnValue = compareByKey(c, a, b));
return returnValue;
}
function compareByKey({ key, order = 'asc' }, a, b) {
const varA = resolvePath(key, a)
const varB = resolvePath(key, b)
let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
if (order === 'desc') {
comparison *= -1
}

return comparison
}

如果find部分令人困惑或丑陋:

另一种方法是reduce每个属性的比较器值。但是,当发现非零值时,这不会短路。

const sortByKey = criteria => 
(a, b) => 
criteria.reduce((acc,c) => acc || compareByKey(c, a, b), 0)

const sortByKey = (criteria) => (a, b) => {
let comparedValue = 0;
for (const c of criteria) {
comparedValue = compareByKey(c, a, b);
if (comparedValue)
return comparedValue;
}

return comparedValue;
}

const arrayOfObjects = [{
name: 'John',
age: 30,
city: 'New York',
details: {
occupation: 'developer',
}
},
{
name: 'Jane',
age: 25,
city: 'Paris',
details: {
occupation: 'designer',
}
},
// added another designer for testing
{
name: 'Jane 2',
age: 30,
city: 'Paris',
details: {
occupation: 'designer',
}
}
];
const sortByKey = (criteria) => (a, b) => {
let returnValue = 0;
criteria.find(c => returnValue = compareByKey(c, a, b));
return returnValue;
}
function compareByKey({ key, order = 'asc' }, a, b) {
const varA = resolvePath(key, a)
const varB = resolvePath(key, b)
let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
if (order === 'desc') {
comparison *= -1
}

return comparison
}
// This function is used to resolve the path of a key in an object
function resolvePath(path, obj) {
return path.split('.').reduce(function(prev, curr) {
return prev ? prev[curr] : null
}, obj || self)
}
console.log(arrayOfObjects.sort(sortByKey([
{ key: 'details.occupation' }, 
{ key: 'age', order: 'desc' }
])))

您可以尝试:

const arrayOfObjects = [{
id: 3,
name: 'Jane',
age: 25,
city: 'Paris',
details: {
occupation: 'designer',
}
},
{
id: 1,
name: 'John',
age: 30,
city: 'New York',
details: {
occupation: 'developer',
}
},
{
id: 2,
name: 'Bob',
age: 25,
city: 'New York',
details: {
occupation: 'developer',
}
},
];
let sortByKey = function (a, b, keys) {
for (let key of keys) {
if (a[key.key] != b[key.key]) return (a[key.key] > b[key.key] ? 1 : -1) * (key.order == 'desc' ? -1 : 1);
}
return 0;
}

let result = arrayOfObjects.sort((a, b) => sortByKey(a, b, [{ key: 'age' }, { key: 'city', order: 'desc' }]));
console.log(result);