Seek and Destroy is destroying my brain

I admit. Seek and Destroy had me stumped. So I cheated and I looked up the answer. Then I went back and re-did all of the Basic Javascript challenges (to try to solidify my understanding) but it’s still got me stumped. Currently, my code filters exactly only the last argument object… I’ve commented in my code what I think it’s doing. I think perhaps I’m using the wrong variables in the filter function? Please give me a pointer or two…

    function destroyer(arr) {
  
      // create an array from the argument object (args) and define our variables. 
      // curr is going to be the current argument we seek
      // output will be our final, filtered array
  
      var args = Array.prototype.slice.call(arguments);
      var curr = args[1];
      var output;
  
  
      // this code doesn't run until called on. It returns elements that don't match curr.
      //I think it does this, but there seems to be a problem with everything but the llast.
      function seek (arr) {
      return arr !== curr;          
    
      } // closes the seek function
  
      // Since we don't know how many arguments there are, this code runs through each, sets it as "current", then calls the seek function which should eliminate respetive argument. But it doesn't.... WHY??
      for (var i = 1; i < args.length; i++) {
        curr = args[i];
        output = arr.filter(seek);
      } // closes for loop
  
      return output;
    } //closes destroy function

    // It seems like only the last argument works. I added a few extra numbers to test. Only 8 is filtered in this case.
    destroyer([3, 5, 1, 8, 9, 4, 6, 2, 2], 2, 3, 5, 9, 8);

Change your line from
> output = arr.filter(seek);
to
> output = output ? output.filter(seek) : arr.filter(seek);

The reason is that with each iteration you’re filtering out values from the starting array, and then with the next iteration you want to proceed with the result from the previous iteration and not filter out values from the original array. Hope this makes sense.

'EDIT I’m wrong - again ! I thought I understood but I don’t , see @JohnL3 's reply :smile:

And for the docs: [ternary condition](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)

I cleaned up your code and added [spoiler] tags.
You need to use triple backticks to post code to the forum.
See this post for details.

To explain this further:

OP, you were constantly redifining output to be the filter of arr and the current argument, so that in the end all that was filtered was the last argument.
output = output ? output.filter(seek) : arr.filter(seek) Tests whether or not output has been defined (ie arr with curr[1] removed), then if it’s been defined it starts to filter out more from there, progressively getting rid of more filters rather than starting from scratch for each filter.

or you can just do arr = arr.filter(seek);

1 Like

just thought id let you know this is incorrect … i understand why you used it as an example but it dosent work the way you were thinking … rather than try explain it i have supplied a link which i think will make it clearer … and as i know you are working hard and enjoy learning i thought you might like my explanation.

1 Like

Thanks a lot - it’s definitely not the first time I get something wrong ! I’ll edit my previous message so as not to mislead more people. Funny how you get used to live with the embarrassment ! :yum:

better to get something wrong and be shown where … rather than getting something wrong and not finding out. Anyway though you would appreciate it being pointed out as they are very useful things to use in your code … so its good to understand them.

if (output) {} is what you were thinking of. It’s just testing whether or not output has been assigned.

1 Like

Oh absolutely - besides having a massive blush when I read your post :grin: I was like "oh ok, let’s learn that then ! "

Check this out:

    function smallestWord(sentenceArray){ 
           var smallest;
           sentenceArray.forEach(function(word){ smallest = !smallest ? word : smallest.length <= word.length ? smallest : word});

           //if smallest hasn't been defined, then make it the first word. Otherwise compare the length of the word in smallest to the length of the next word. 
           //then if the length of the word in smallest is smaller than or equal to the length of the next word, keep the word in smallest. If it's larger then make smallest the next word.

           return smallest;
    }
    smallestWord(["This", "is", "a", "sentence"]) //====> "a"

If you don’t know forEach, then it’s basically a loop but instead of iterating one at a time it iterates on the whole thing at once. word is the same thing as sentenceArray[i] would be in a for loop. Filter works the same way.

Okay thank vdineva, your code worked. And thanks to tomotheap for the link on ternary conditions. Now I know what to study next!

fuqted thanks for your feedback… I think I meant arr = arr.filtered(seek) and now that I see that, my original mistake is embarrassing.

Thanks everyone!

Hi @elsalvadordali

As a fun tidbit, using ES6/ES7 you can actually write this function in 3 lines of code.

function destroyer(arr, ...args) {
  return arr.filter(item => !args.includes(item));
}

It’s not too crazy:

  • The 3 dots are the rest operator (ES7), basically it combines the ‘rest’ of the arguments into an array called args. This takes over the job of slicing the arguments array.
  • Includes (ES6) is a new array method that is essentially shorthand for args.indexOf(item) !== -1
  • The => is the arrow operator (ES6), which is another form of function. Used like this it has an implicit return statement

Anyway, thought I’d share :stuck_out_tongue:

2 Likes

Wow @joesmith100. Just wow. I had to google es6 and es7 but man… you’re like a Javascript god. I know I’m only learning the basics now and that includes thinking like a programmer… Would your way be the recommended way to write it? Because I thought I read that the “legibility” of your code was the most important thing, though I guess that’s a matter of perspective as well.

Lol, cheers, I wouldn’t say I was a JavaScript God, just very inquisitive. I also definitely didn’t come up with that solution when I first ran through it :stuck_out_tongue:.

I wouldn’t say it’s recommended unless you fully understand what’s going on. I would definitely recommend looking into the newest features at some point, but I’d just stick with the basics for now.

Your right, it is all a matter of perspective, to me, that code is perfectly legible; although, if I had read that a year ago my brain would have probably exploded :grin:

ES5 looks like

function destroyer(arr) {
    var args = Array.from(arguments).slice(1);
    return arr.filter(function(item){return args.indexOf(item) === -1});
}

So not too crazy

Array.from is actually an ES6 method, so in ES5 you would need still need to use:

var args = Array.prototype.slice.call(arguments, 1);

But yea, not too crazy as you said :grin:

Or var args = Array.apply(null, arguments).slice(1)

My solution :

function destroyer(arr) {
// Remove all the values
var args = Array.prototype.slice.call(arguments);
arr = arr.filter(val => {return args.indexOf(val) === -1;});
return arr;
}
destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3);

Hi everyone. I just finished this task on my own without any call function involved.
My solution doesn’t look as good as yours but it does the job. Tell me what do you think. Here is my code:

function destroyer(arr) {
  var filterItems = function (query) {
    return args[0].filter(function(el) {
     return el !== query;
    });
  };
  var args = Array.from(arguments);
  var itemsToRemove = args.slice(1);
  for(var i=0;i<itemsToRemove.length;i++){
    args[0] = filterItems(itemsToRemove[i]);
  }
  return args[0];
}