30秒学会 JavaScript 片段 · 2023年5月11日

30秒学会 JavaScript 片段 – Partition a JavaScript array into two or more arrays based on a condition

Array partitioning is often useful when processing data. Conceptually, partitioning an array into two is very similar to filtering, but instead of removing elements from the array, we group them based on the truthiness of the provided function. For more than two partitions, the concept is fairly similar, but the implementation is a little more nuanced.

Partition array into two

A two-partition is the simplest case and requires very little work. All we have to do is use Array.prototype.reduce() to create an array of two arrays. Then, we call the given function and use Array.prototype.push() to add elements for which fn returns true to the first array and elements for which fn returns false to the second one.

代码实现

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 }]
// ]

Partition array into multiple arrays

Partitioning an array into an arbitrary number of arrays, based on the return value of the provided function, poses a little more of a challenge. We can still make use of Array.prototype.reduce(), but instead of using an array of two arrays as the accumulator, we’ll use a Map object. This will allow us to group the elements into as many arrays as we need.

It also allows us to easily check if a partition already exists via the use of Map.prototype.has(). If it does, we can simply add the element to the existing partition. If it doesn’t, we can create a new partition with an array containing the element.

Finally, we use Map.prototype.values() to get an iterator over the values of the Map object and use the spread operator (...) to convert it to an array.

使用样例

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]]

翻译自:https://www.30secondsofcode.org/js/s/partition-array