8

I want to filter a array by keeping the same array without creating a new one.

with Array.filter() :

getFiltersConfig() {
  return this.config.filter((topLevelConfig) => topLevelConfig.name !== 'origin')
}

what is the best way to get the same result by filtering by value without returning a new array ?

Azzabi Haythem
  • 2,318
  • 7
  • 26
  • 32
Mouad Ennaciri
  • 1,217
  • 3
  • 15
  • 28

4 Answers4

7

For completeness, I thought it might make sense to show a mutated array variant.

Below is a snippet with a simple function mutationFilter, this will filter the array directly, notice in this function the loop goes in reverse, this is a technique for deleting items with a mutated array.

Also a couple of tests to show how Array.filter creates a new array, and mutationFilter does not.

Although in most cases creating a new array with Array.filter is normally what you want. One advantage of using a mutated array, is that you can pass the array by reference, without you would need to wrap the array inside another object. Another advantage of course is memory, if your array was huge, inline filtering would take less memory.

let arr = ['a','b','a'];
let ref = arr; //keep reference of original arr

function mutationFilter(arr, cb) {
  for (let l = arr.length - 1; l >= 0; l -= 1) {
    if (!cb(arr[l])) arr.splice(l, 1);
  }
}

const cond = x => x !== 'a';

const filtered = arr.filter(cond);
mutationFilter(arr, cond);

console.log(`ref === array -> ${ref === arr}`);
console.log(arr);

console.log(`ref === filtered -> ${ref === filtered}`);
console.log(filtered);
Keith
  • 22,005
  • 2
  • 27
  • 44
  • This is a cool solution, but I'm confused by the sample code. Why would ref === arr? ref still contains three elements, and arr only one. – Robert M. Jun 09 '23 at 06:21
  • @RobertM. Late reply here, both `ref` & `arr` will contain only 1, that's the side effect mutation will have, and is often the reason of confusion and is the reason it usually advised against. – Keith Jul 30 '23 at 12:10
  • Oh, I see, ref contains the same number of elements as arr because it's a *reference* to the original array. I was missing that. – Robert M. Jul 31 '23 at 18:17
1

I want to filter a array by keeping the same array without creating a new one.

what is the best way to get the same result by filtering by value without returning a new array ?

I have an answer for the second criterion, but violates the first. I suspect that you may want to "not create a new one" specifically because you only want to preserve the reference to the array, not because you don't want to create a new array, necessarily (e.g. for memory concerns).

What you could do is create a temp array of what you want

var temp = this.config.filter((topLevelConfig) => topLevelConfig.name !== 'origin')

Then set the length of the original array to 0 and push.apply() the values "in-place"

this.config.length = 0; //clears the array
this.config.push.apply(this.config, temp); //adds what you want to the array of the same reference
Busman
  • 575
  • 2
  • 6
  • 14
  • 1
    This is a clever solution, for a particular use case. I wish the OP had been more specific about why he wanted this. – Robert M. Jun 09 '23 at 06:38
-1

You could define you custom method like so:

if(!Array.prototype.filterThis){
  Array.prototype.filterThis = function (callBack){
          if(typeof callBack !== 'function')
              throw new TypeError('Argument must of type <function>');
    let t = [...this];
    this.length = 0;
    for(let e of t) if(callBack(e)) this.push(e);
          return this;
  }
}

let a = [1,2,3,4,5,5,1,5];
a.filterThis(x=>x!=5);
console.log(a);

Warning: Be very cautious in altering built in prototypes. I would even say unless your making a polyfill don't touch. The errors it can cause can be very subtle and very hard to debug.

A Rogue Otaku
  • 913
  • 10
  • 20
  • Be very cautious in altering built in prototypes. I would even say unless your making a polyfill don't touch. The errors it can cause can be very subtle and very hard to debug. – Keith May 24 '19 at 15:52
  • @Keith, I did not overwrite any built-ins. I made a new method. – A Rogue Otaku May 24 '19 at 15:55
  • No you altered the prototype of the built-in Array.. For more details about why -> https://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice – Keith May 24 '19 at 15:57
  • @Keith. Yeah got your point. Basically since it's not standard method. A method with this name might later be added by ES Spec and then it would cause problems right? – A Rogue Otaku May 24 '19 at 15:59
  • Yeah, you never know ES Spec one day may add a `filterThis` method :) It's happened before, apparently MooTools added a contains method to the prototype, and actually conflicted with ES6 contains causing no end of trouble. – Keith May 24 '19 at 16:03
  • Hmmn.. I'm just gonna a add a check for `filterThis` in my code if it already Exists or not and add a warning Text below with your comment. I'm not gonna remove the answer though. This will remind me next time when I try to alter built-in prototypes. :D – A Rogue Otaku May 24 '19 at 16:06
-6

Not sure why would you want to do mutation but if you really want to do it, maybe assign it back to itself?

let arr = ['a','b','a'];

arr = arr.filter(x => x !== 'a');

console.log(arr)
Isaac
  • 12,042
  • 16
  • 52
  • 116
  • 15
    @MouadEnnaciri For future reference, remember this is not mutating the array, it's creating a new one. – Keith May 24 '19 at 13:35
  • Yeah. This is NOT what they asked for. Sure it is in the same variable, but it is a new array. – Intervalia May 24 '19 at 15:25
  • @Keith what can go wrong if I create a new one while using the same variable? – Ooker Jul 30 '23 at 10:56
  • @Ooker Nothing!, but it's not mutating the array like the OP asked for. Maybe the OP miss understood what mutating means as this became the accepted answer. But based on the the title is totally incorrect and might explain the down-votes. – Keith Jul 30 '23 at 12:03