freeCodeCamp Algorithm Challenge Guide: Seek and Destroy


#1

:triangular_flag_on_post: Remember to use Read-Search-Ask if you get stuck. Try to pair program :busts_in_silhouette: and write your own code :pencil:

:checkered_flag: 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. Many people hardcode this program for three arguments. You will remove any number from the first argument that is the same as any other other arguments.

Relevant Links

:speech_balloon: Hint: 1

You need to work with arguments as if it was a regular array. The best way is to convert it into one.

try to solve the problem now

:speech_balloon: Hint: 2

You need to filter, this also means you need to create a callback function. You can use various methods like: indexOf(), includes(). If you need another approach, reduce() might also be of use; keep reading those docs!

try to solve the problem now

:speech_balloon: Hint: 3

To convert arguments into an array use this code var args = Array.prototype.slice.call(arguments);

try to solve the problem now

Spoiler Alert!

687474703a2f2f7777772e796f75726472756d2e636f6d2f796f75726472756d2f696d616765732f323030372f31302f31302f7265645f7761726e696e675f7369676e5f322e676966.gif

Solution ahead!

:beginner: Basic Code Solution:

function destroyer(arr) {
  var args = Array.prototype.slice.call(arguments);

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

:rocket: Run Code

Code Explanation:

  1. Create an array of arguments using Array.prototype.slice.call() and store it in the variable args. We’ll use this to check against arr.
  • Start a basic for loop to iterate through arr. Nest another for loop inside the first, changing the integer variable j and arr to args. This second loop will iterate through args .

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

  • If the value at the current index is equal in both arrays, use delete to remove it from arr.

  • Outside of the nested loops: return the modified array using the Boolean object as a filter for any null's created by the delete operator.

Relevant Links

:sunflower: Intermediate Code Solution:

function destroyer(arr) {
  var args = Array.from(arguments).slice(1);
  return arr.filter(function(val) {
    return !args.includes(val);
  });
}

:rocket: Run Code

Code Explanation:

  1. Declare a variable named args and set it equal to a new Array object from() the arguments passed into the function. On the same or next line, use the slice() method on args starting from the second index, 1. This separates the arguments used for filtering into their own array of args.
  • Return the filtered array, using includes() in the callback function to check if val is not in args; returning true to keep the value in the original array or false to remove it.

Relevant Links

:clipboard: NOTES FOR CONTRIBUTIONS:

  • :warning: DO NOT add solutions that are similar to any existing solutions. If you think it is similar but better, then try to merge (or replace) the existing similar solution.
  • Add an explanation of your solution.
  • Categorize the solution in one of the following categories — Basic, Intermediate and Advanced. :traffic_light:
  • Please add your username only if you have added any relevant main contents. (:warning: DO NOT remove any existing usernames)

See :point_right: Wiki Challenge Solution Template for reference.


Seek & Destroy - need help understanding (arguments)
Please explain for loop in Seek and Destroy
Basic Algorithm Scripting problem: Seek and Destroy, Get hint. Intermediate code solution. explanation?
#2

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?


#3

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


#4

Made an edit using both


#5

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


#6

Will do, sorry about that


#7

#8

#9

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.


#10

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.


#11

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.


#12

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);


#13

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.


#14

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?


#15

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);
  
}

#16

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:


#17

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);

#18

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);


#19

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);

#20

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);