skip to Main Content

I want to get the result of filter() but also the elements that were removed in the process. For example, I want to get [1] as a result of the normal filter operation as well as [2, 3] in the following execution:

[1, 2, 3].filter(num => num <= 1)

Currently, I’m doing it like this – is there a better and faster way?

function filter() {
  const removedNumbers = [];

  const newArray = [1, 2, 3].filter((num) => {
    if (num > 1) {
      removedNumbers.push(num);
      return false;
    }
    return true;
  });

  return {
    newArray,
    removedNumbers,
  };
}
console.log(filter())

2

Answers


  1. Maybe try Object.groupBy, but be aware of its coverage.

    const array = [1, 2, 3];
    const { true: filtered, false: removed } = Object.groupBy(array, e => e > 1);
    
    console.log({ filtered, removed });
    Login or Signup to reply.
  2. You can use Array::reduce(), seems faster than Object.groupBy().

    There’s a known problem with the new flatMap() that it uses iterators and notoriously slower exactly known 6.2x times.

    Seems a similar fate befell Object.groupBy():

    const [filtered, removed] = [1,2,3].reduce((r, num) => (r[+(num <= 1)].push(num), r), [[],[]]);
    console.log({filtered, removed});
    ` Chrome/122
    -------------------------------------------------------------------------------------
    >                        n=100      |     n=1000     |    n=10000    |    n=100000   
    Array::reduce()     1.00x   x1m 490 | 1.00x x10k 146 | 1.00x x1k 180 | 1.00x x100 227
    Object.groupBy();   3.61x x100k 177 | 1.25x x10k 183 | 1.08x x1k 195 | 1.62x x100 368
    -------------------------------------------------------------------------------------
    https://github.com/silentmantra/benchmark `
    
    const $chunk = () => Array.from({length:100}, () => Math.random()*2);
    const $input = [];
    
    // @benchmark Object.groupBy();
    const { true: filtered, false: removed } = Object.groupBy($input, e => e > 1);
    ({filtered, removed});
    
    // @benchmark Array::reduce()
    {
    const [filtered, removed] = $input.reduce((r, num) => (r[+(num <= 1)].push(num), r), [[],[]]);
    ({filtered, removed});
    }
    
    /*@skip*/ fetch('https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js').then(r => r.text().then(eval));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search