Skip to content

在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' }
]
*/