2

New to JS. Doing a practice exercise in which I want to remove some specific items from an array and return the original array back without those items. I did it one way, but the sample solution was completely different and I want to try and understand it.

Is my line of thinking correct (see comments after each line of code below)? I think I understand, but I'm not sure if my reasoning is the correct reasoning or if I just lucked into it. I want to be sure I fully understand the next time I see something like this.

const pull = (arr, ...args) => {
        // In this case, arr = arra1 and ...args = the values "a" and "c"
    let argState = Array.isArray(args[0]) ? args[0] : args;     
        // I think this is saying, "Is the first item (index[0]) in arra1 included in the list of the arguments that follow (in this case, "a" and "c")?"
        // The value of arra1[0] is "a", which is indeed one of the arguments that follow, so the ternary operator would return false and give you the "args", which are "a" and "c" in this case.
        // "a" and "c" form an array (do they? I may be wrong here), so Array.isArray() would evaluate to true, and therefore argState = true
    let pulled = arr.filter((v, i) => !argState.includes(v));
        // I think this is saying, "Loop through arra1. v is the first value, "a" in this case. "Does argState contain the value "a"? 
        // It does, so it will come back true which will evaluate to false when we apply the "!". So "a" is NOT filtered into the new array called "pulled". 
        // Second loop, does argState contain the value "b"? It does not, so it will come back false, which will evaluate to true when we apply the "!". So "b" IS filtered into the new array called "pulled". 
        // And so on and so forth, and we would end up with "pulled = [ b , b ]" for this line.
    arr.length = 0;
        // I believe this just empties the original arr, or arra1 in this case. So arra1 = [ ]
    pulled.forEach(v => arr.push(v));
        // Now we loop through "pulled" and push each value onto arra1
    return pulled;
        // This will return the original arra1 with the new values [ b, b ]
  };

let arra1 = ['a', 'b', 'c', 'a', 'b', 'c'];
console.log(pull(arra1, 'a', 'c')); // will return ["b","b"]

My main confusion stems from the !argState.includes(v) part. If argState in our previous line ended up with a value of true or false, it doesn't make sense to me that we can check if argState includes a value (v) from the arra1 array (i.e. "a", "b", or "c" in this exercise). How could argState include values like this when it was already set to just the value true or false because of the Array.IsArray() check?

Katie Reynolds
  • 317
  • 2
  • 16
  • 1
    I stumbled on the the name `filter` enough times that I ended up just mentally interpreting .`filter()` to be `.keep()` or `selectFrom()` – aeischeid Mar 28 '21 at 04:18
  • That’s a really good way to think about it. I’ll remember that to avoid confusion next time, thanks! – Katie Reynolds Mar 28 '21 at 13:15

2 Answers2

2

How could argState include values like this when it was already set to just the value true or false because of the Array.IsArray() check?

It's not set to true or false. It's set to an array:

let argState = Array.isArray(args[0]) ? args[0] : args;   

If args[0] is an array, it's set to that array. Otherwise, it's set to the whole args array.

This is equivalent to

let argState;
if (Array.isArray(args[0])) {
  argState = args[0];
} else {
  argState = args;
}

This allows callers to use either the format

pull(someArr, ['foo', 'bar'])

or

pull(someArr, 'foo', 'bar')

and the use of the conditional operator to construct argState then collects an array of ['foo', 'bar'] regardless of the format the caller used.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thank you!! This is where my disconnect was. I kept seeing Array.isArray as being on the OUTSIDE of the ternary. I was so confused as to how args[0] would evaluate to true or false on its own! I see now that it’s saying “if args[0] is an array...”. Makes perfect sense now! – Katie Reynolds Mar 28 '21 at 04:20
0

Question has been answered! My disconnect occurred at this line:

let argState = Array.isArray(args[0]) ? args[0] : args;

My mind kept reading this line as: "If args[0] is true, return args[0]. If false, return args. Then, if what is returned is an array, make argState = true. If not, make argState = false."

Instead of the correct way to read it: "If args[0] is an array and therefore true, return args[0]. If false, return args."

This would set argState equal to some values, rather than just true or false.

Many thanks to @CertainPerformance for helping me realize my mistake!

Katie Reynolds
  • 317
  • 2
  • 16