在JavaScript中对对象数组进行排序
您是否曾经想过对对象数组进行排序,但感觉太复杂了?毕竟,Array.prototype.sort()
可以根据您的需求进行自定义排序,但是比较多个属性和顺序可能会有些麻烦。让我们解决这个问题并创建一个强大、可重用的解决方案。
按属性和顺序对对象数组进行排序
经典的场景可以追溯到SQL查询,您可以按多个列进行排序,并为每个列指定顺序。这个需求为我们定义了函数签名。
该函数应接受一个对象数组、一个属性数组和一个顺序数组。后两个数组的长度和元素顺序应相匹配。顺序数组应为可选的整数数组(正数表示升序,负数表示降序)。如果未提供顺序数组,则默认顺序应为升序。
在确定了函数签名之后,我们可以开始实现该函数。第一步是使用扩展运算符(...
)创建数组的副本。这样可以避免改变原始数组。
然后,我们使用Array.prototype.sort()
对数组进行排序,这是我们进行重要工作的地方。使用Array.prototype.reduce()
,我们遍历属性数组并比较当前属性的值。
累加器的默认值为0
,这意味着当前属性对于两个对象来说是相等的。如果累加器为0
,我们比较当前属性的值。如果累加器不等于0
,我们返回它,这意味着我们可以跳过剩下的属性,因为对象已经排序好了。
const orderBy = (arr, props, orders) =>
[...arr].sort((a, b) =>
props.reduce((acc, prop, i) => {
if (acc === 0) {
const [p1, p2] =
orders && orders[i] <= 0
? [b[prop], a[prop]]
: [a[prop], b[prop]];
acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0;
}
return acc;
}, 0)
);
const users = [
{ name: 'fred', age: 48 },
{ name: 'barney', age: 36 },
{ name: 'fred', age: 40 },
];
按照指定的属性和顺序对数组中的对象进行排序
另一个使用对象排序算法的用例是根据**属性顺序**对对象数组进行排序。这可以是优先级顺序,其中一个值不是按字母或数字顺序较大,而是具有更高的优先级。
与前面的代码片段不同,该函数应该接受一个对象数组,一个属性的名称作为字符串,以及一个按顺序排列的值的数组。如果后者不包含所有可能的值,则它们将被视为具有**最低优先级**。
在开始对数组进行排序之前,我们从顺序数组创建一个对象,其中值是键,索引是值。这样我们就可以快速检查一个值的顺序。之后,我们使用`Array.prototype.sort()`并根据我们的顺序对象比较属性的值。
```js
const orderWith = (arr, prop, order) => {
const orderValues = order.reduce((acc, v, i) => {
acc[v] = i;
return acc;
}, {});
return [...arr].sort((a, b) => {
if (orderValues[a[prop]] === undefined) return 1;
if (orderValues[b[prop]] === undefined) return -1;
return orderValues[a[prop]] - orderValues[b[prop]];
});
};
const users = [
{ name: 'fred', language: 'Javascript' },
{ name: 'barney', language: 'TypeScript' },
{ name: 'frannie', language: 'Javascript' },
{ name: 'anna', language: 'Java' },
{ name: 'jimmy' },
{ name: 'nicky', language: 'Python' },
];
orderWith(users, 'language', ['Javascript', 'TypeScript', 'Java']);
/*
[
{ name: 'fred', language: 'Javascript' },
{ name: 'frannie', language: 'Javascript' },
{ name: 'barney', language: 'TypeScript' },
{ name: 'anna', language: 'Java' },
{ name: 'jimmy' },
{ name: 'nicky', language: 'Python' }
]
*/