Perseids Perseids - 6 months ago 19
Javascript Question

What is the in-place alternative to Array.prototype.filter()

I've got an array that I would like to remove some elements from. I can't use

Array.prototype.filter()
, because I want to modify the array in place (because it saves a memory allocation and, more important for me, makes the code more simple in my use case). Is there an in-place alternative to
filter
that I can use, maybe analogously to how
Array.prototype.forEach()
can be used as an in-place variant to
Array.prototype.map()
?

Edit: Minimum example upon request:

function someCallback(array) {
// do some stuff
array.filterInPlace(function(elem) {
var result = /* some logic */
return result;
})
// do some more stuff
}

Answer

Is there an in-place alternative to filter

No, but it's not hard to write your own. Here is an approach which squeezes out all the values which fail a condition.

function filterInPlace(a, condition) {
  let i = 0, j = 0;

  while (i < a.length) {
    const val = a[i];
    if (condition(val, i, a)) a[j++] = val;
    i++;
  }

  a.length = j;
  return a;
}

condition is designed to have the same signature as the callback passed to Array#filter, namely (value, index, array). For complete compatibility with Array#filter, you could also accept a third thisArg parameter.

Using forEach

Using forEach has the minor advantage that it will skip empty slots. This version also implements thisArg and does a minor optimization of skipping the assignment if we have not yet encountered a failing element.

function filterInPlace(a, condition, thisArg) {
  let j = 0, squeezing = false;

  a.forEach((e, i) => { 
    if (condition.call(thisArg, e, i, a)) {
      if (squeezing) a[j] = e; 
      j++;
    } else squeezing = true;
  });

  a.length = j;
  return a;
}