freecodecamp Challenges- Seek and Destroy - javascript

I am trying to solve this challenge Seek and Destroy. I can't figure out what is wrong. Any help ?
Seek and Destroy
You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
This is the initial code below:
function destroyer(arr) {
// Remove all the values
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
This is my Code below:
function destroyer(arr) {
var letsDestroyThis = [];
var i =1 ; while (i<arguments.length) {
letsDestroyThis.push(arguments[i]);
i++;
}
for(var j=0 ; j< arguments[0].length; j++) {
for (var k= 0; k< letsDestroyThis.length; k++) {
if(arguments[0][j] === letsDestroyThis[k]){
arguments[0].splice(j, 1);
}
}
}
return arguments[0];
}
destroyer([2, 3, 2, 3], 2, 3);
Thanks in Advance!

You can create an array of all values that are supposed to be removed. Then use Array.filter to filter out these values.
Note: Array.splice will change original array.
function destroyer() {
var arr = arguments[0];
var params = [];
// Create array of all elements to be removed
for (var k = 1; k < arguments.length; k++)
params.push(arguments[k]);
// return all not matching values
return arr.filter(function(item) {
return params.indexOf(item) < 0;
});
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

function destroyer(arr) {
/* Put all arguments in an array using spread operator and remove elements
starting from 1 using slice intead of splice so as not to mutate the initial array */
const args = [...arguments].slice(1);
/* Check whether arguments include elements from an array and return all that
do not include(false) */
return arr.filter(el => !args.includes(el));
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

This worked for me:
function destroyer(arr) {
// Remove all the values
var args = Array.from(arguments);
var filter = [];
for (i = 0; i < args[0].length; i++) {
for (j = 1; j < args.length; j++) {
if (args[0][i] === args[j]) {
delete args[0][i];
}
}
}
return args[0].filter(function(x) {
return Boolean(x);
});
}
console.log(
destroyer([1, 2, 3, 1, 2, 3], 2, 3)
);

//two ways of resolving the Seek and Destroy challenge on the FreeCodeCamp
//I was trying to simplify this code, please post your solutions, simplifying the code
//as much has its possible
function destroyer1 (arr){
//get array from arguments
var args = Array.prototype.slice.call(arguments);
args.splice(0,1);
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(function(value){
return Boolean(value);
});
}
//--------------------------------------
function destroyer(arr) {
// Remove all the values
//Get values from arguments of the function to an array, index 0(arr[0] will be "arr",
//rest of indexes will be rest of arguments.
var args = Array.from(arguments);
for (var i = 0 ; i < args[0].length; i++){
for (var j = 1; j < args.length; j++){
if(args[0][i] === args[j]){
delete args[0][i];
}
}
}
return args[0].filter(function(value){
return Boolean(value);
});
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
console.log(destroyer1([1,6,3,9,8,1,1], 3,1));

This is my Code:
function destroyer(arr) {
var argsBeRemove = [...arguments];
argsBeRemove.shift();
return arr.filter(val => {
return argsBeRemove.indexOf(val) == -1;
});
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

Here is my version of Seek and Destroy. I assume that there are no zero elements in input (that assumption allows to pass the challenge). But that way I can make found elements equal zero and then just filter them out. It is pretty straight forward and no index mess when deleting elements in for loops.
function destroyer(arr) {
// Remove all the values
var args = Array.prototype.slice.call(arguments);
var temp = [];
temp = arguments[0].slice();
for (j = 1; j < args.length; j++) {
for (i = 0; i < arguments[0].length; i++) {
if (arguments[0][i] == arguments[j]) {
temp[i] = 0;
}
}
}
function isZero(value) {
return value !== 0;
}
var filtered = temp.filter(isZero);
return filtered;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

function destroyer(arr) {
var args = Array.prototype.slice.call(arguments, 1);
return arr.filter(destroyNum);
function destroyNum(element) {
return !args.includes(element);
}
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

Give this a shot, it is way less convoluted:
function destroyer(arr) {
// arr1 is equal to the array inside arr
var arr1 = arr.slice(arguments);
// arr2 becomes an array with the arguments 2 & 3
var arr2 = Array.prototype.slice.call(arguments, 1);
// this function compares the two and returns an array with elements not equal to the arguments
return arr1.concat(arr2).filter(function(item) {
return !arr1.includes(item) || !arr2.includes(item)
})
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);

You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
The accepted solution returns a new array, instead of removing the elements from the existing array.
This can be achieved efficiently by iterating the array in reverse and removing any elements matching any of the filter arguments.
function destroy(original, ...matches) {
if('length' in original) {
let index = original.length
while(--index > -1) {
if(matches.includes(original[index])) {
original.splice(index, 1)
}
}
}
return original;
}
const original = [1, 2, 3, 1, 2, 3]
destroy(original, 2, 3)
console.log(original);

My answer is similar to previous one, but I didn't use indexOf. Instead of that I checked the values in cycle, but compiler gives me a warning to not to declare function in cycle.
function destroyer(arr) {
// Remove all the values
var temp = [];
for (var i = 1; i < arguments.length; i++) {
temp.push(arguments[i]);
arr = arguments[0].filter(function(value) {
return ( value !== temp[i - 1]) ;
});
}
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);

We can get the arguments behind the array, which are the number required to be removed and store them to a list. Then, we can just use a filter to filter out the numbers that needed to be removed.
function destroyer(arr) {
let removeList=[...arguments].slice(1);
return arr.filter(e=>removeList.indexOf(e)===-1);
}

I know isn't the shortest way to do it, but i think is the more simple to understand in an intermediate level.
function destroyer(arr, ...elements) {
var i =0;
while(i<=arr.length){ //for each element into array
for(let j =0; j<elements.length; j++){ //foreach "elements"
if(arr[i]==elements[j]){ // Compare element arr==element
arr.splice(i,1); //If are equal delete from arr
i--; //Check again the same position
j=0;
break; //Stop for loop
}
}
i++;
}
return arr;
}
console.log(destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan"));
console.log(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3));

function destroyer(arr) {
let newArray = Array.from(arguments).splice(1)
return arr.filter(item => !(newArray.includes(item)))
}

Related

How to find the largest group of numbers in an array and return them separately in javascript?

How can I make a function that returns only the numbers greater than the number that I entered?
My code here isn't working, and I don't know why.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var num = Number(prompt('number'));
function findBiggestNumbers(num) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] > num) {
num = arr[i];
}
}
return num;
// }
console.log(findBiggestNumbers(num));
To work with arrays you could use the filter function, it returns a subset of the array with some condition. So, you can simpley do:
var num = 5; //using 5 as an example
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var b = a.filter(number => number > num);
You can put this into an function.
You need to create a new empty array and fill it with numbers that are bigger than input value.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var num = Number(prompt('number'));
function FindBiggestNumbers(num) {
let biggerThanArray = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] > num) {
biggerThanArray.push(arr[i]);
}
}
return biggerThanArray;
}
console.log(FindBiggestNumbers(num));
You can start to understand and do some fun things with functional JS.
Similar to the answer from Daladier Sampaio I've used filter to return an array where each element passes a condition (el > num) in the callback function. (filter, reduce, and map were introduced in ES5 and are very useful array methods and well worth learning how to use.)
In this example, I've passed in - and called - a whole function named greaterThan instead.
greaterThan
1) Accepts an argument - n, the number from the prompt in this case
2) Returns an array - the callback function that will operate on each array element. What's interesting about this function is that it carries a copy of num with it when it returns. A function like this that retains a copy of its outer lexical environment like that is called a closure. Understanding what they are and how they work is a useful JS skill, and one that is often picked up on in JS interviews.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const num = Number(prompt('number'));
// accepts a number and returns a callback function
// that accepts an array element and
// tests it against the value of `n`
function greaterThan(n) {
return function (el) {
return el > n;
};
}
// calling greater than with our prompted number
// returns that new callback function that checks each
// array element
const out = arr.filter(greaterThan(num));
console.log(out);
Modern JS >= ES6 will allow you to condense the amount of code you have to write using arrow functions. The following one-line code will work in place of the function in the example:
const greaterThan = n => el => el > n;
You could use Array.prototype.filter():
function FindBiggestNumbers(num) {
return arr.filter(n => n > num);
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var number = Number(prompt("Enter a number"));
console.log(FindBiggestNumbers(number));
The alternative is using a nested if statement inside a for loop like so:
First make a new array:
function FindBiggestNumbers(num) {
var newArr = [];
}
Then loop through the original array:
function FindBiggestNumbers(num) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
}
}
And if you find an element of the array greater than the number, add it to the new array:
function FindBiggestNumbers(num) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] > num) {
newArr.push(arr[i]);
}
}
}
Finally, return the new array:
function FindBiggestNumbers(num) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] > num) {
newArr.push(arr[i]);
}
}
return newArr;
}
Demonstration:
function FindBiggestNumbers(num) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] > num) {
newArr.push(arr[i]);
}
}
return newArr;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var number = Number(prompt("Enter a number"));
console.log(FindBiggestNumbers(number));

Filtering arguments through an argument, why will this not work?

I want to remove all the arguments from the array passed in function destroyer which was passed as arguments.
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments); //turns arguments into arrays
function checkArgs() {
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(checkArgs);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); //Remove 2nd, 3rd, etc arguments from first argument...??
The .filter callback requires you to return what should be in the filtered result.
From MDN:
Return value
A new array with the elements that pass the test. If no
elements pass the test, an empty array will be returned.
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments); // turns arguments into arrays
function checkArgs() {
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < args.length; j++) {
if (arr[i] == args[j]) {
delete arr[i];
}
}
}
// You have to return something in the filter callback
return arr;
}
return arr.filter(checkArgs);
}
//remove 2nd, 3rd, etc arguments from first argument
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
console.log(destroyer([1, 2, 3, 1, 2, 3], 3));
The .filter require a return value as a filtered value. And also argumnents also contains the array arr at position 0 so you have to start from position 1.
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments); //turns arguments into arrays
function checkArgs() {
for (var i = 0; i < arr.length; i++) {
for (var j = 1; j < args.length; j++) {
if (arr[i] == args[j]) {
delete arr[i];
}
}
}
return arr;
}
return arr.filter(checkArgs);
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
Here is a slightly simplified version for the filter. There are other ways you can optimize this as well. This is assuming a 0-based index.
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments); // turns arguments into arrays
return args[0].filter(function(item, index) {
return args.indexOf(index) < 0;
});
}
//remove 2nd, 3rd, etc arguments from first argument
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

What is the difference between [4,null,6] and [4,6]

Here is the question:
Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays.
And here is my code:
function diffArray(arr1, arr2) {
var newArr = [];
// Same, same; but different.
for (i = 0; i < arr1.length; i++) {
for (j = 0; j < arr2.length; j++)
while (arr1[i] === arr2[j])
delete arr2[j];
newArr = arr2;
}
return newArr;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
Please, tell me my mistakes.
If you work using indices as references which you delete, you'll leave those indices undefined.
You have to use push to add an item and splice to remove one.
The time complexity of the following code should be: O(nm) where n and m are the lengths of the arr1 and arr2 arrays respectively.
function diffArray(arr1, arr2) {
var newArr = [];
for (i = 0; i < arr1.length; i++) {
for (j = 0; j < arr2.length; j++)
while (arr1[i] === arr2[j])
arr2.splice(j, 1);
newArr = arr2;
}
return newArr;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
This should work, but I've found a different way that is a bit slower for short arrays but much faster for longer array.
The time complexity of the following code should be: O(3(n + m)), which is reduced to O(n + m) where n and m are the lengths of the arr1 and arr2 arrays respectively.
Look at this fiddle.
Here's it:
function diffArray(arr1, arr2) {
let obj1 = {}, obj2 = {};
for (let l = arr1.length, i = 0; i < l; i++)
obj1[arr1[i]] = undefined;
for (let l = arr2.length, i = 0; i < l; i++)
obj2[arr2[i]] = undefined;
let a = [];
for (let arr = arr1.concat(arr2), l = arr.length, i = 0, item = arr[0]; i < l; i++, item = arr[i])
if (item in obj1 !== item in obj2)
a.push(item);
return a;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]));
The task you are trying to complete asks you to create a new array, but instead you modify arr2. It would probably be easiest to just copy all elements not included in the other array to a new array, like this:
function diffArray(arr1, arr2) {
var newArray = [];
arr1.forEach(function(el) {
if (!arr2.includes(el)) {
newArray.push(el);
}
});
arr2.forEach(function(el) {
if (!arr1.includes(el)) {
newArray.push(el);
}
});
return newArray;
}
If you would rather try and fix your code instead, I can try to have another look at it.
I've used Array.prototype.filter method:
function diffArray(arr1, arr2) {
var dif01 = arr1.filter(function (t) {
return arr2.indexOf(t) === -1;
});
var dif02 = arr2.filter(function (t) {
return arr1.indexOf(t) === -1;
});
return (dif01).concat(dif02);
}
alert(diffArray([1, 2, 3, 6, 5], [1, 2, 3, 4, 7, 5]));
If you still want to use your code and delete the common elements, try to use Array.prototype.splice method instead of delete: the latter deletes the value, but keeps the index empty, while Array.prototype.splice will remove those whole indices within the given range and will reindex the items next to the range.
You can use Array.prototype.filter:
var array1 = [1, 2, 3, 5];
var array2 = [1, 2, 3, 4, 5];
var filteredArray = filter(array1, array2).concat(filter(array2, array1));
function filter(arr1, arr2) {
return arr1.filter(function(el) { return arr2.indexOf(el) < 0; });
}
Here is a working JSFiddle.
Try this:
function diffArray(arr1, arr2) {
var ret = [];
function checkElem(arrFrom, arrIn) {
for (var i = 0; i < arrFrom.length; ++i) {
var elem = arrFrom[i];
if (arrIn.indexOf(elem) === -1)
ret.push(elem);
}
}
checkElem(arr1, arr2);
checkElem(arr2, arr1);
return ret;
}
I hope this can solve your problem.

Filtering arguments from Arrays

The following code should take a given array and filter out all arguments that follow. For example the below code should return: [1, 1].
function destroyer(arr) {
var args= [];
args.push(arguments[0]);
var realArgs = args[0];
var filteredArr=[];
function removeIt (val){
return val != ;
}
filteredArr= realArgs.filter(removeIt);
return filteredArr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
I can't figure out the filter function. Do I need to use Boolean somehow?
If you want to access the arguments of the function you should use arguments not args. The filtering part is not straightforward because javascript still doesn't have a builtin function we can use, so we have to implement it by ourselves (that's the includes function).
function destroyer(arr) {
var arr = arguments[0];
var toFilter = [];
for (var i = 0; i < arguments.length; i++)
toFilter.push(arguments[i]);
function removeIt (arr, numsToFilter){
var array = arr.slice(); // make sure to copy the array in order not to modify the original
for (var i = 0; i < array.length; i++) {
if (includes(numsToFilter, array[i])) {
delete array[i];
}
}
return array;
}
function includes(arr, k) {
for(var i=0; i < arr.length; i++){
if( arr[i] === k){
return true;
}
}
return false;
}
return removeIt(arr, toFilter);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Running the code-example
You can call Array#slice on the arguments object to convert it to an array. We'll slice from the index 1 (skip the arr). Then you can Array#filter the arr array. On each iteration check if the item is in the toRemove array by using Array#indexOf. Items that are in toRemove will be filtered out. Note - Array#filter returns a new array.
function destroyer(arr) {
// convert all the arguments but arr into array
var toRemove = [].slice.call(arguments, 1);
// filter the original array
return arr.filter(function removeIt(val){
// keep all vals that are not in the toRemove array
return toRemove.indexOf(val) === -1;
});
}
var result = destroyer([1, 2, 3, 1, 2, 3], 2, 3);
console.log(result);

Remove element from array if given in argument

I'm trying to get a hang of JavaScript (again) and so far it's not going great.
The challenge:
You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
Why doesn't the code below remove the required elements for the second test case?
function destroyer(arr) {
console.log(arguments);
for (var array_i = 0; array_i < arr.length; array_i++){
for (var arg_i = 1; arg_i < arguments.length; arg_i++){
console.log("indexes", array_i, arg_i);
if (arr[array_i] === arguments[arg_i]){
console.log(arr[array_i], arguments[arg_i], "destroyed");
arr.splice(array_i, 1);
console.log(arr, arguments);
array_i = 0;
arg_i = 1;
}
}
}
return arr;
}
It successfully works here:
destroyer([3, 5, 1, 2, 2], 2, 3, 5);
But not here:
destroyer([2, 3, 2, 3], 2, 3);
You're trying to compensate for the elements deleted along the way by resetting your indices. It's much simpler (and actually works) if you delete from the end of the array. No resets needed.
function destroyer(arr) {
for (var array_i = arr.length - 1; array_i >= 0; array_i--){
for (var arg_i = 1; arg_i < arguments.length; arg_i++){
if (arr[array_i] === arguments[arg_i]){
arr.splice(array_i, 1);
break;
}
}
}
return arr;
}
console.log( destroyer([2, 3, 4, 2, 3], 2, 3) ); // [4]
console.log( destroyer([2, 3, 2, 3], 2, 3) ); // []
The problem is that you modify the array while you're looping.
You can use filter function to do the same:
function destroyer(arr) {
var args = [].slice.call(arguments);
return arr.filter(function(item) {
return args.indexOf(item) == -1;
});
}
document.getElementById('output').innerHTML =
JSON.stringify(destroyer([2,3,2,3], 2, 3)) + "\n" +
JSON.stringify(destroyer([1,2,3,4,2,3], 2, 3))
<pre id="output"></pre>
An alternative to reverse iteration using ES5 methods, and modifying the original array.
function destroyer(arr) {
var rest = Array.prototype.slice.call(arguments, 1);
rest.forEach(function(unwanted) {
var index = arr.indexOf(unwanted);
while (index > -1) {
arr.splice(index, 1);
index = arr.indexOf(unwanted);
}
});
return arr;
}
var initial1 = [2, 3, 2, 3];
destroyer(initial1, 2, 3);
document.getElementById('out1').textContent = JSON.stringify(initial1);
console.log(initial1);
var initial2 = [3, 5, 1, 2, 2];
destroyer(initial2, 2, 3, 5);
document.getElementById('out2').textContent = JSON.stringify(initial2);
console.log(initial2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.4.1/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<pre id="out1"></pre>
<pre id="out2"></pre>
The problem here is you are relying on length to loop through the element of array and simultaneously you are rearranging the elements of the array.
So what happens is after removing the 2 and 3, 2 again comes at 0th place and your counter is ahead now and will never cover the position 0th. So there will be other case too in which you will not get the desired result.
So instead of this try looping through each argument only once,
Select an argument and then search for it in the array.
for(var i = 1; i < arguments.length; i++)
{
var index = arr.indexOf(arguments[i]);
while(index > -1)
{
arr.splice(index, 1);
index = arr.indexOf(arguments[i]);
}
}
And you will get what you want.

Categories

Resources