Seek and Destroy - Basic Alogorithm Scripting - Help

I can use the first argument in my array filter if I set the index manually, i.e args[0]. How do I iterate through args to make the filter work properly?

// Filter args from array
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments, 1);
console.log(args);
var destroyedArr = arr.filter(function (val) {
return val != args[0];
});
console.log(destroyedArr);
return destroyedArr;
}

    destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Any help greatly appreciated.
1 Like

You can manually iterate by setting up a loop to perform .filter() once for each additional argument.
hint: get the number of additional arguments by using the .length property

2 Likes

Thank you for your reply xarimus, I will give that a go.

1 Like

@Taramouse did you figure out how to iterate through args?

I tried not to do it manually but I can’t figure it out

function destroyer(arr) {
var args = Array.prototype.slice.call(arguments, 1);
var newArray = arr.filter(function(val) {
for (i = 0; i < args.length; i++) {
return (val !== args[i]);}
});
return newArray;
}

// Filter args from array

destroyer([1, 2, 3, 1, 2, 3], 2, 3);

I also had problems with this one.
I realized that the for loop does not work as intended inside the callback function since we are using a return statement in the very next line. Hence the loop will always only run once and variable i does not get incremented.

A possible solution might be to move the for loop outside the function -

function destroyer(arr) {
  var newArray = arr;    
  var args = Array.prototype.slice.call(arguments, 1);
  for (var i = 0; i < args.length; i++) {
    newArray = newArray.filter(function(val) {return (val !== args[i]);});
  }
  return newArray
}

The reassignment to newArray is important because each iteration of the for loop changes the array.
So, the first iteration will remove all instances of the first argument from arr,
the second iteration will remove all instances of the second argument from arr, and so on…

I struggled quite a bit with this one too! :confused::slight_smile:

5 Likes

Only problem with the above is that it gives a warning : “Don’t make functions within a loop”

I don’t think I understand enough javascript to grasp the significance of that warning in this context.

1 Like

I managed to solve it in the end.

I used the filter to call a function which looped through each argument and returned either false if the argument matched an element in the array (to be destroyed), or true if the element could remain in the array.

I hope this can put you on the right track, it’s the best explanation I can give short of actually posting the answer.

2 Likes

Hi Taramouse,

I figured out a way to make sure the filter work properly. But my callback function need to compare the value in array with every argument. As long as the result of every comparison is always true, it means that this value should remain(return ture). Otherwise this value should be deleted(return false).

code as follows:

`function destroyer(arr) {
  // Remove all the values
  
  var result = [];
  var condition = Array.prototype.slice.call(arguments, 1);
  
  
  var destroy = function(value){
    var temp = [];//store result of every comparison
    var reality = true;
    for(var i=0; i<condition.length; i++){
      temp.push(value !== condition[i]);
      reality = reality && temp[i];
    }
    
    return reality;
    
      
      
    };



result = arr.filter(destroy);

return result;
}`

If you use the other way to make it, please tell me. I’d love to learn other ways:)

I converted the arguments to be removed to an array and then filtered the array, removing each one.

function destroyer(arr) {
  Array.prototype.slice.call(arguments).slice(1)
    .forEach(bullet => arr = arr.filter(target => target !== bullet));
  return arr;
}
3 Likes

The thing to remember is that whatever code is contained in the loop will be executed on each iteration. If you define a function inside of a loop, the compiler is going to have to reinitialize that function every time the loop runs, which is a waste of electricity. In fact, it’s generally best to declare anything the loop will use outside of the loop and only declare inside of the loop what you really need to. This even goes for our good friend, arr.length.

Instead of

for(var i = 0; i < arr.length; i++) {
//Stuff...
}

We ought to be doing this:

for(var i = 0, length = arr.length; i < length; i++) {
//Stuff
}

In the first example, arr.length gets checked every time the for loop ends, which incurs a slight penalty to performance as it must do an object property lookup. The second example caches the length as a number, so the lookup is much faster. This is the same principle as regards declaring functions inside of loops, and this sort of optimization will be important as the number of iterations gets much larger.

4 Likes

Thank you PortableStick, I have seen example for loops written like that but not used it as I didn’t understand why the extra variable for arr.length was needed, I also thought the length variable would be recreated at each iteration, whereas arr.length would be stored only once.

Now thinking about it, the i variable obviously isn’t recreated else the whole loop would not work, so why would it happen to the length variable?

I hate the thought of using unnecessary CPU time and memory, or as you stated, electricity. Scale it all up to a larger application and it’s the stuff of nightmares.

Your explanation makes perfect sense so I’m off to rewrite all my loops…

1 Like

The for loop declaration has 3 parts, delimited by semicolons:

for(var i = 0; i < arr.length; i++)

The first is where we generally just initialize the variable i and declare its value 0. Anything before this first semicolon happens before the loop starts, and you can define as much as you want (with obvious practical considerations for readability). The following for loop is completely identical to the previous:

var i = 0
for(;i < arr.length;i++)

The second and third parts are invoked on each iteration, and every time you access a property of any object (arr.length, for example), you’re performing a lookup. This is why storing the length is faster, because we’re only accessing the length property of arr once and referring forevermore to the variable length.

2 Likes

@PortableStick Excellent and interesting explanation once again. Thank you very much.

1 Like

I did this:

Do you guys like it? Hate it?

2 Likes

I don’t get it tddaniel114. If you set “var values = args[0]” doesn’t that just set it to “1”?

hey there,your code is elegant…can you explain what inputArray.filter( (x) => args.indexOf(x) === -1); does?..also let args = […arguments]; does this means grab all the value stored in arguements object and save it in args?

okey thanks for the link…quick follow up when you do
let args = […arguements]; this means args will have [[1, 2, 3, 1, 2, 3], 2, 3] right?
so when you do args.indexOf(x) where x is a member of inputArray, wont this also check inside the subarray in args?

Thank you man…i actually learned something new today :slight_smile: some i cant figure like /*jshint esnext: true */ looks like a comment but its actually executed.

HI Guys

Here is my solution

function destroyer (arr,a,b,c) {

   var result = arr.filter(function(val) {

     return (val!=a && val!=b && val!=c);

 });

return result;
}

destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3);

The problem with this solution is that it will not work with more than three numbers, and the instructions say that one or more numbers may be used. I would recommend using a loop!