Skip to content

根据条件将JavaScript数组分成两个或多个数组

在处理数据时,数组的分割通常很有用。从概念上讲,将数组分割成两个数组与过滤非常相似,但不是从数组中删除元素,而是根据提供的函数的真值将它们分组。对于多个分区,概念上非常相似,但实现上稍微复杂一些。

将数组分割成两个

两个分区是最简单的情况,需要很少的工作。我们只需要使用Array.prototype.reduce()创建一个包含两个数组的数组。然后,我们调用给定的函数,并使用Array.prototype.push()fn返回true的元素添加到第一个数组中,将fn返回false的元素添加到第二个数组中。

const partition = (arr, fn) =>
  arr.reduce(
    (acc, val, i, arr) => {
      acc[fn(val, i, arr) ? 0 : 1].push(val);
      return acc;
    },
    [[], []]
  );

const users = [
  { user: 'barney', age: 36, active: false },
  { user: 'fred', age: 40, active: true },
];
partition(users, o => o.active);
// [
//   [{ user: 'fred', age: 40, active: true }],
//   [{ user: 'barney', age: 36, active: false }]
// ]

将数组分割成多个数组

根据提供的函数的返回值,将数组分割成任意数量的数组会更具挑战性一些。我们仍然可以利用Array.prototype.reduce(),但是不再使用包含两个数组的数组作为累加器,而是使用Map对象。这将允许我们将元素分组成所需数量的数组

它还允许我们通过使用Map.prototype.has()来轻松检查分区是否已存在。如果存在,我们可以将元素简单地添加到现有分区中。如果不存在,我们可以创建一个包含该元素的数组的新分区。

最后,我们使用Map.prototype.values()获取Map对象的值的迭代器,并使用扩展运算符(...)将其转换为数组。

const partitionBy = (arr, fn) => [
  ...arr
    .reduce((acc, val, i, arr) => {
      const current = fn(val, i, arr);
      if (acc.has(current)) acc.get(current).push(val);
      else acc.set(current, [val]);
      return acc;
    }, new Map())
    .values(),
];

const numbers = [1, 1, 3, 3, 4, 5, 5, 5];

partitionBy(numbers, n => n % 3);
// [[1, 1, 4], [3, 3], [5, 5, 5]]
partitionBy(numbers, n => n);
// [[1, 1], [3, 3], [4], [5, 5, 5]]