Skip to content

Home

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

More like this

Start typing a keyphrase to see matching snippets.