Strange output with Array.filter() method - javascript

In the code below I expected the result of destroyer([1, 2, 3, 1, 2, 3], 2, 3); would be [1,1].
But the result pops out to be [1,2,3,1,2,3].
Where am I going wrong?
function destroyer(arr) {
function hlp(x) {
for(var i=1; i<arguments.length ; i++) {
if(x == arguments[i]) return false;
}
return true;
}
return arr.filter(hlp);
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

You can use ES6 rest parameter syntax and check if array includes any of those parameters using include()
function destroyer(arr, ...rest) {
function hlp(e) {
return !rest.includes(e)
}
return arr.filter(hlp);
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
If you want to use for loop and arguments your code should look like this.
function destroyer(arr) {
var arg = arguments
function hlp(x) {
for (var i = 1; i < arg.length; i++) {
if (x == arg[i]) return false;
}
return true;
}
return arg[0].filter(hlp);
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

You've defined destroyer to only accept one argument, while you're passing in more than one. arguments is undefined, and iterating in a function passed to Array.filter() isn't a good idea. Array.filter() checks every element for you. Not that it would work in your code, but if it would, it would be better to just return x == arguments[i] instead of checking whether it's true or false. If you return x == arguments[i] you're actually returning a boolean. An example of that is where I in the code below return exclude.indexOf(i) == -1;. Try the following approach instead:
function destroyer(arr, exclude) {
return arr.filter(function(i) {
return exclude.indexOf(i) == -1;
});
}
console.log(destroyer([1, 2, 3, 1, 2, 3], [2, 3]));

Solved in two ways:
1st:
function destroyer(arr) {
function hlp(x) {
for(var i=1; i<destroyer.arguments.length ; i++) {
if(x == destroyer.arguments[i]) return false;
}
return true;
}
return arr.filter(hlp);
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
2nd
Look to the solution posted by #Nenad Vracar

Related

Confusing behavior with JavaScript Arguments object

I have the following piece of code:
function destroyer(arr) {
for(var i=1; i<arguments.length; i++){
var kill = arguments[i];
arr = arr.filter(function(x){return x != kill;});
}
return arr;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
It removes the elements from an array which equal the optional arguments. This code gives [1,1] as I expect.
But if I change the 4th line to
arr = arr.filter(function(x){return x != arguments[i];});
I get [1,2,3,1,2,3] instead, when I expect [1,1]. Why is that the case?
Because when you use arguments within the anonymous function, you're accessing arguments of that function, not destroyer().
You will need to copy the arguments of destroyer(), preferably before your loop as follows:
function destroyer(arr) {
var args = arguments;
for(var i=1; i < args.length; i++)
{
arr = arr.filter(function(x){return x != args[i];});
}
return arr;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
Alternatively, an arrow function can also be used to achieve the same functionality:
function destroyer(arr) {
for(var i=1; i<arguments.length; i++){
arr = arr.filter(x => x != arguments[i]);
}
return arr;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));

Javascript parameters passing

This is the code I have been given. I looked around and I don't quite understand.
This is my question function destroyer accepts one parameter an array but when its being called 3 parameters are sent: an array and 2 integers.
How can I access the two integer parameters in the function if they haven't been passed? Is there something in Javascript that would allow this?
function destroyer(arr) {
// Remove all the value;
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
You can use arguments variable in your function to get a list of passed arguments.
// ES5
function destroyer(arr) {
var pieces = Array.prototype.splice.call(arguments, 1);
var i = 0;
while (arr[i]) {
-1 === pieces.indexOf(arr[i]) ? i++ : arr.splice(i, 1);
}
return arr;
}
// ES6
function destroyer2(arr, ...pieces) {
var i = 0;
while (arr[i]) {
-1 === pieces.indexOf(arr[i]) ? i++ : arr.splice(i, 1);
}
return arr;
}
console.log(JSON.stringify(destroyer([1, 2, 3, 1, 2, 3], 3, 1)));
console.log(JSON.stringify(destroyer2([1, 2, 3, 1, 2, 3], 2, 3)));

Javascript VArgs - not understanding arguments objects with unknown input

So this is a bit of a newbie troubleshooting question. I am doing an exercise of freecodecamp, and I am having an issue parsing the input to my function. It's short, and I think I can cut to the chase if I just show you the code:
function destroyer(arr) {
// Remove all the values
console.log("---");
console.log("arr: " + arr);
var args = Array.from(arr);
console.log(args);
var in_i = arr[0];
return in_i.filter(function (x) {
if (args.indexOf(x) !== -1) {
return true;
} else {
return false;
}
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
which gives me in the console (and I think this is the strange part):
---
arr: 1,2,3,1,2,3
[1, 2, 3, 1, 2, 3]
Clearly I'm not understanding something about arguments objects, or else something is broken. In my experience, the latter is exceedingly uncommon. I would have expected the Array.from(arr) to give an array object: [[1, 2, 3, 1, 2, 3], 2, 3].
The function function destroyer(arr) accepts only 1 parameter in the function destroyer which is an array [1, 2, 3, 1, 2, 3] and ignore the other arguments 2, 3. So, the arr is [1, 2, 3, 1, 2, 3].
If you need to access all the parameters passed to the function, then you can make use of arguments object which is an array like object. arguments would point to the array [[1, 2, 3, 1, 2, 3], 2, 3]. Following code should display the Arguments passed.
function destroyer(arr, param2, param3) {
// Remove all the values
console.log(arguments);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
If your function takes 3 parameters as shown below, param2, param3 have been added, then you can access the value 2, 3 inside your function.
function destroyer(arr, param2, param3) {
// Remove all the values
console.log("---");
console.log("arr: " + arr);
var args = Array.from(arr);
console.log(args);
var in_i = arr[0];
return in_i.filter(function (x) {
if (args.indexOf(x) !== -1) {
return true;
} else {
return false;
}
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
In fact, the part that confused me was that on MDN, the use of the arguments variable was not just illustrative, it's a built-in variable. After #Agalo pointed out that the values I was getting on the console were just the array, it clicked for me.
The solution was to access the extra arguments through the built-in arguments object which automatically has the (reserved) name arguments. Code is like so (for completeness, I should note that I also had false and true switched in the return statements):
function destroyer(arr) {
// Remove all the values
var args_l = arguments.length;
var args = Array.from(arguments);
console.log(args);
var in_i = args.shift();
return in_i.filter(function (x) {
if (args.indexOf(x) !== -1) {
return false;
} else {
return true;
}
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
To riff off of Agalo, you'll note you don't actually need the param2, param3 arguments in the function definition to get the exact same output:
function destroyer(arr) {
// Remove all the values
console.log(arguments);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
At the risk of putting too fine a point on it:
function args_tester(a) {
console.log("a: " + a);
console.log("arguments: " + arguments);
console.log("arguments_as_array: " + Array.from(arguments));
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
args_tester("a", "b", "c");

Using filter() and Arguments object. Logical Error?

Aim of Script: An array and multiple arguments are passed into a function. An array must be returned, minus the elements that are the same as the arguments.
There are no Syntax errors and I can't seem to figure out the fault in my logic.
function destroyer(arr) {
function isTheDestroyer(x) {
//Using the arguments object
for (i=1; i<arguments.length; i++) {
if (x == arguments[i]) {
return false;
}
}
return true;
}
var filtered = arguments[0].filter(isTheDestroyer);
return filtered;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
The output is unchanged when I run it.
I agree with #James Thorpe. arguments in isTheDestroyer is not the same that arguments in destroyer (in reality it's not in same order). I recommend to you to use a closure
function destroyer(arr) {
var args = arguments;
function isTheDestroyer(x) {
//Using the arguments object
for (i=1; i<args .length; i++) {
if (x == args [i]) {
return false;
}
}
return true;
}
var filtered = arguments[0].filter(isTheDestroyer);
return filtered;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);

JavaScript filter callback that uses arguments

The goal is to filter an array and remove all occurrences of elements specified in its argument list.
For example, given removeElements([1, 2, 3, 1, 2, 3,4], 2, 3), my output should be [1,1,4].
function removeElements(arr) {
//I got an error that says **functions** not allowed **inside loop**
for(var i=1;i<arguments.length;i++){
arr= arr.filter(function(e){
return e!==arguments[i];
});
}
return arr;
}
Second thing I tried is moving the filter out of the for loop.
function removeElements(arr) {
function isNotEqual(e){
return e!==this;
}
for(var i=1;i<arguments.length;i++){
arr= arr.filter(isNotEqual,arguments[i]);
}
return arr;
}
None of them work. It always return arr as [1,2,3,1,2,3,4].
Can you please tell as to what is wrong in my usage? Or what is the approach for using filter in this scenario?
You can use Array.prototype.slice to get the blacklisted elements in array form.
Then use Array.prototype.indexOf to see if a given element is in the array for the filter function.
http://jsfiddle.net/Loothof7/
function removeElements(arr) {
var blacklist = Array.prototype.slice.call(arguments, 1);
return arr.filter(function(e) {
return blacklist.indexOf(e) == -1;
});
}
alert(removeElements([1, 2, 3, 1, 2, 3,4], 2, 3));
Note that Function.prototype.call is used on Array.prototype.slice with the this scope argument of arguments instead of directly calling arguments.slice since arguments isn't actually a "real" array.
To try to explain the reasons the snippets didn't succeed:
Every function defines its own arguments, even when the function is embedded.
function removeElements(arr) {
console.log(arguments);
// Arguments {
// 0: Array [1, 2, 3, 1, 2, 3, 4],
// 1: 2,
// 2: 3
// }
arr = arr.filter(function (e) {
console.log(arguments);
// Arguments {
// 0: 1, 2, 3, 1, ... (each value in `arr`)
// 1: 0, 1, 2, 3, ... (each index)
// 2: Array [1, 2, 3, 1, 2, 3, 4] (`arr` itself)
// }
// ...
});
return arr;
}
removeElements([1, 2, 3, 1, 2, 3, 4], 2, 3);
By retrieving values from arguments inside of the iterator (function(e) {...}), the statement will compare e against values in the 2nd Arguments.
for(var i=1;i<arguments.length;i++){
arr = arr.filter(function(e){
// 1st = 0 (the first index from `arr`)
// 2nd = [1, 2, 3, ...] (the `arr` itself)
console.log(arguments[i]);
return e!==arguments[i];
});
}
One option to resolve this is to access arguments outside of the iterator function, stashing the value in a variable that won't have the same conflict:
for(var i=1;i<arguments.length;i++){
var skip = arguments[i];
arr = arr.filter(function (e) {
return e !== skip;
});
}
http://jsfiddle.net/y7evq6nq/
If you're not using strict mode, the value of this will always be an Object.
When you provide a primitive value for a thisArg, it will be boxed into its equivalent Object type. In this case, a new Number.
function foo() {
console.log(typeof this, this); // 'object' Number(3)
return true;
}
[0].filter(foo, 3);
And, since === first checks for type equality, a primitive and boxed number cannot be equal:
var number = 3;
var boxedNumber = new Number(3);
console.log(typeof number); // 'number'
console.log(typeof boxedNumber); // 'object'
console.log(typeof number === typeof boxedNumber); // false
console.log(number === boxedNumber); // false
You can use the .valueOf() method to retrieve the primitive value from the object.
function isNotEqual(e){
return e!==this.valueOf();
}
http://jsfiddle.net/ow9b78bf/
Or, you can try using strict mode, which allows this to hold a primitive value without boxing it.
arguments are function specific pseudo-variable. Using it inside callback will give arguments of callback and not outer function.
function removeElements(arr) {
var args = Array.prototype.slice.call(arguments);
for(var i=1;i<args.length;i++){
arr= arr.filter(function(e){
return e!==args[i];
});
}
}
I have already answered this type of question here any way I post it to you
A simple function
function filter(){
var j = -1;
for(var i = 1; i < arguments.length; i++){
j = arguments[0].indexOf(arguments[i]);
if(j > -1){
arguments[0].splice(j, 1);
}
}
return arguments[0];
}
you can call this function with no of args eg:
filter([1,2,3,4,5,6,7,8,9], 1, 3, 5); //return [2,4,6,7,8,9]
filter([1,2,3,4,5,6,7,8,9], 1); //return [2,3,4,5,6,7,8,9]
This will use a callback function to check against the two numbers given in the arguments list.
function removeElements(arr, num1, num2){
return arr.filter(numChecks(num1, num2));
}
function numChecks(num1, num2){
return function(element){
return element !== num1 && element !== num2;
}
}
removeElements([1, 2, 3, 1, 2, 3,4], 2, 3)
I think this is what you want to do, maybe I'm wrong.
var result = [1, 2, 3, 1, 2, 3, 4].filter(function(item) {
return item !== 1 && item !== 2;
});
console.log(result); // [3, 3, 4]
UPDATE:
This function can do the job you want passing the items to be remove as an array instead of turning the arguments[1] param an Array using slice.call():
function removeItems(arr, items) {
return arr.filter(function (elem) {
return items.indexOf(elem) === -1;
});
}
var result = removeItems([1, 2, 3, 1, 2, 3, 4], [2, 3]);
console.log(result); // [1, 1, 4]
There are really good answers here, but you can do it very clean in this way, remember you have an objects option in filter method which you can use in the callback function, in this case i'm using it like : arguments[i] so I can check every value in the arguments array
function destroyer(arr) {
for(var i = 1; i < arguments.length; i++){
arr = arr.filter(isIn, arguments[i]);
}
function isIn(element,index, array){
if (element != this){
return element;
}
}
return arr;
}

Categories