freeCodeCamp Challenge Guide: Seek and Destroy

Seek and Destroy


Problem Explanation

This problem is a bit tricky because you have to familiarize yourself with Arguments, as you will have to work with two or more but on the script you only see two. You will remove any number from the first argument that is the same as any of the other arguments.

Relevant Links


Hints

Hint 1

The rest parameter syntax allows the function to accept an indefinite number of arguments, placed into an array. If you use the arguments object convert it into a regular array.

Hint 2

You may want to use various methods like: indexOf(), includes(), or filter(). When in doubt about any function, check the MDN docs!


Solutions

Solution 1 (Click to Show/Hide)
function destroyer(arr) {
  const valsToRemove = Object.values(arguments).slice(1);
  const filteredArray = [];

  for (let i = 0; i < arr.length; i++) {
    let removeElement = false;
    for (let j = 0; j < valsToRemove.length; j++) {
      if (arr[i] === valsToRemove[j]) {
        removeElement = true;
      }
    }
    if (!removeElement) {
      filteredArray.push(arr[i]);
    }
  }
  return filteredArray;
}

Code Explanation

  1. Create an array of valsToRemove using Object.values(arguments).slice(1) and store it in the variable valsToRemove. We’ll use this to check against arr.

  2. Start a basic for loop to iterate through arr. Nest another for loop inside the first, changing the integer variable j and arr to valsToRemove. This second loop will iterate through valsToRemove .

    • Within the second loop create an if statement, checking strictly === that the current value of arr[i] is equal to valsToRemove[j].

    • If the value at the current index is equal in both arrays, let removeElement to true remove it from arr.

    • If the value is not flagged for removal, add it the the filteredArray.

  3. Outside of the nested loops, return the filteredArray.

Relevant Links

Solution 2 (Click to Show/Hide)
function destroyer(arr) {
  const valsToRemove = Array.from(arguments).slice(1);
  return arr.filter(function(val) {
    return !valsToRemove.includes(val);
  });
}

Code Explanation

  1. Declare a variable named valsToRemove and set it equal to a new Array object from() the arguments passed into the function. Use the slice() method on the array of arguments, starting from the second index, 1.

  2. Return the filtered array, using includes() in the callback function to check if val is not in valsToRemove; returning true to keep the value in the original array or false to remove it.

Relevant Links

Solution 3 (Click to Show/Hide)
function destroyer(arr, ...valsToRemove) {
  return arr.filter(elem => !valsToRemove.includes(elem));
}

Code Explanation

  • Using spread operator to retrieve the arguments.
  • Return the filtered array, using includes().

Relevant Links

134 Likes

Why use var args = Array.prototype.slice.call(arguments) when var args = Array.from(arguments) does the same job in a seemingly more elegant and concise way?

18 Likes

They are two valid ways, i just listed one. You are free to use either one.

16 Likes

Made an edit using both

2 Likes

Please update the sample code, they all have the same old link. @Cairos

2 Likes

Will do, sorry about that

2 Likes

Hi. I just finished this exercise and found out that my code is nowhere near the answer. However, it works. Can someone check if I did it right, and what points did I miss if ever? Here’s my code:

function destroyer(arr) {
arr = arguments[0];
var res= [];
for (var i = 1; i < arguments.length; i++) {
console.log(arguments[i]);
for (var j = 0; j < arr.length; j++) {
  if (arr[j] === arguments[i]) {
    delete arr[j];
    console.log(arr);
  }
}
}
  for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
    if (arr[i]) {
      res.push(arr[i]);
    }
  }
return res;
}

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

As you can see I didn’t use the filter method. However, I found out that I can actually do arr.filter(Boolean); to remove the null values inside the array. Can someone enlighten me about the Array.prototype.slice.call(arguments) and why I need to use is instead of setting my array to arguments[0]? Thank you.

5 Likes

I wanted to build upon my previous mutation solution, because this algorithm is about keeping the mutations, so I used my previous algorithm to find them, and used filter() to keep them:

function destroyer(arr) {
var targets = Array.prototype.slice.call(arguments, 1);

return arr.filter(function(val){
for(var i = 0; i < targets.length; i++){
if(targets.indexOf(val) < 0)
return true;
}
return false;
});
}

@gsuxlzt The spread operator which you are using is another way to achieve the similar result (Spread Operator), I instead use it to get an array with the targets to keep to compare against the main array.

6 Likes

You don’t need to assign arguments[0] to arr, arr is already arguments[0].Since there is only one named parameter in the function, it only references the first element of arguments.

The other arguments are put an array by using Array.prototype.slice.call(arguments).

the slice() method is used by an array to copy an array, but because arguments is not really an array(it’s an array-like object), you can’t do arguments.slice(1).So we use Array.prototype.slice.call(arguments, 1) to force arguments to use the slice method, as if it is an array.

10 Likes

I’ve just passed this task and found out that my solution is much simpler but it also works and I hope it could be useful for the understanding of basic algorithm of the method filter.

function destroyer(arr, val1, val2, val3) {

function filterForFalsy (arr) {
if (arr !== val1 && arr !== val2 && arr !=val3) {

  return arr;   
}  

}

return arr.filter(filterForFalsy);
}

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

8 Likes

I used a similar solution but realized that it will only work for up to 3 arguments. It passes all the tests on the exercise but the directions say 1 or more arguments so it should work for any number of arguments.

6 Likes

I am really confused and hopefully someone will be able to help me. Why does:

return arr; // only returns the first argument?

Is arr an object or an array?

6 Likes

I did the same thing, couldn’t figure out how to create a callback function that would work with filter, still don’t really understand how the filter works.

function destroyer(arr) {

  var args = arr.slice.call(arguments); 
  
 
    for (j=0; j<arr.length; j++){
      for (i=1; i<arguments.length; i++){
        if (arguments[i] === arr[j]){
          delete arr[j];
          
        }
      }
    }
  
  return arr.filter(Boolean);
  
}

arr is a normal array

arr only returns the first argument because arr is the first argument. The other arguments 2, and 3, are not arr, they don’t have a parameter name because it was never set. Instead to access them you have to call them by arguments[1] and arguments[2].

arr can also be called arguments[0].

Hope that helps :slight_smile:

15 Likes

Here’s my solution:

function destroyer(arr) {
  // Remove all the values
  var arrOfArgs = [];
  for (var i = 1; i < arguments.length; i++) {
    arrOfArgs.push(arguments[i]);
  }
  
  function filterArgs(value) {
    return !arrOfArgs.includes(value);
  }
  return arr.filter(filterArgs);
}

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

I think my solution is simple and works well.

function isValid(value) {
if(this == value) {
return false;
} else {
return true;
}
}
function destroyer(arr) {
// Remove all the values
for(var i = 0; i < arguments.length; i++) {
arr = arr.filter(isValid,arguments[i]);
}
return arr;
}

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

Here’s my overly simplistic solution :triumph:

function destroyer(arr) {
  // Create two new arrays. One for the main array and another for unwanted chars.
  var unwanted = [];
  var givenArr = arguments[0];
  
  // Push all other args to the unwanted array
  for (var i = 1; i < arguments.length; i++) {
    unwanted.push(arguments[i]);
  }
  
  // A function for testing if a member of the unwanted array matches a char of main array.
  function tester (value) {
    if (unwanted.includes(value)) {
      return false;
    } else {
      return true;
    }
  }
  
  // filter out chars which donot meet the above criteria
  var filtered = givenArr.filter(tester);
  
  // return the filtered array to the console.
  return filtered;
}

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

Another solution!

function destroyer(arr) {      
  // newArr comprises an array of all arguments passed in,
  // slicing off the first
  var newArr = Array.from(arguments).slice(1);
  
  // fllter arr values against newArr values in line below
  arr = arr.filter(function(val) {
  
      // use ternary to return false if newArr val is in arr, else true
      return (newArr.includes(val)) ? false : true;
  });
  
// return updated arr
  return arr;

}

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