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));
Related
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
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);
This question already has answers here:
JavaScript variable number of arguments to function
(12 answers)
Closed 7 years ago.
My function needs to accept any number of lists, then output their symmetric difference. sym([1, 2, 3], [5, 2, 1, 4]) should return [3, 5, 4] and sym([1, 2, 5], [2, 3, 5], [3, 4, 5]) should return [1, 4, 5]. How can I deal with the unknown number of arguments? I thought that I could use the single variable args to create a list of lists, but that isn't working.
function isin(num,arra)
{
for (i=0; i<arra.length; i++)
{
if (num == arra[i]){return true;}
}
return false;
}
function sym(args) {
var syms = [];
console.log(args);
for (i=0; i<args.length; i++)
{
var ins = false;
for (j=0; j<args[i].length; j++)
{
for (k=i+1; k < args.length; k++)
{
if(isin(args[i][j], args[k]))
{
ins = true;
}
}
}
if (ins === false)
{
syms.push(args[i][j]);
}
}
return syms;
}
sym([1, 2, 3], [5, 2, 1, 4]);
use arguments, not args
and you dont need to have it in the function definition.
(note: Im assuming the rest of your code works once you actually get what youre expecting passed in)
so:
function sym() {
var syms = [];
console.log(arguments);
for (i=0; i<argumentss.length; i++)
{
var ins = false;
for (j=0; j<arguments[i].length; j++)
{
for (k=i+1; k < arguments.length; k++)
{
if(isin(arguments[i][j], arguments[k]))
{
ins = true;
}
}
}
if (ins === false)
{
syms.push(arguments[i][j]);
}
}
return syms;
}
For arrays with numbers:
function sym() {
var temp = {}, res = [];
for (var q=0; q<arguments.length; ++q) {
for (var w=0; w<arguments[q].length; ++w) {
temp[arguments[q][w]] ^= 1;
}
}
for (var key in temp) {
if (temp[key] === 1) {
res.push(+key);
}
}
return res;
}
console.log(sym([1, 2, 3], [5, 2, 1, 4]), sym([1, 2, 5], [2, 3, 5], [3, 4, 5]))
Es6 introduces rest paramters. You can use it instead of arguments object.
function logAllArguments(...args) {
for (var arg of args) {
console.log(arg);
}
}
logAllArguments(1,2,3)
Within in each function scope you have access to the arguments object . Any parameters you pass in will available inside of it. You can convert the arguments object to an array using Array.prototype.slice.apply(null,arguments) , and iterate over it.
My function needs to accept any number of lists, then output their symmetric difference. sym([1, 2, 3], [5, 2, 1, 4]) should return [3, 5, 4] and sym([1, 2, 5], [2, 3, 5], [3, 4, 5]) should return [1, 4, 5]. I am confused by the result of my code - this returns an empty array.
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
{
if (num == arra[i])
{
return true;
}
}
return false;
}
function sym()
{
console.log("logging args");
console.log(arguments); // logs [Array[3], Array[4]]
var syms = [];
for (var i=0; i<arguments.length-1; i++)
{
var ins = false;
for (var j=0; j<arguments[i].length; j++)
{
for (var k=i+1; k < arguments.length; k++)
{
if(isin(arguments[i][j], arguments[k]))
{
ins = true;
}
}
}
if (ins === false)
{
syms.push(arguments[i][j]);
}
}
return syms;
}
sym([1, 2, 3], [5, 2, 1, 4]);
EDITED: to add some code
Your loop variables are all global, including i. Put a var in front of them (at least before i) and you're done.
The following gets the symmetric difference of two sets. I hope you can get on from there.
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
{
if (num == arra[i]){return true;}
}
return false;
}
function sym()
{
var j,k,i,l;
var syms = [];
for ( i=0; i<arguments.length; i++)
{
var ins = false;
for (k=i+1; k < arguments.length; k++){
for ( j=0; j<arguments[i].length; j++){
if(!isin(arguments[i][j], arguments[k]))
{
syms.push(arguments[i][j]);
}
}
for ( l=0; l<arguments[k].length; l++){
if(!isin(arguments[k][l], arguments[i]))
{
syms.push(arguments[k][l]);
}
}
}
}
return syms;
}
sym([1, 2, 3], [5, 2, 1, 4]);
my code returns an array of undefined values
This is because when you are pushing onto syms, your for-loop with the j variable has completed. So it is actually at j = <arguments[i].length (now it really is an out-of-bounds index read).
if (ins === false)
{
syms.push(arguments[i][j]); # push "undefined" onto syms.
}
Make sure you put this block of code inside the for (var j=0; j<arguments[i].length; j++) block.
To solve the symmetric difference of multiple arrays, we can start by designing a function which returns the symmetric difference of two arrays
As shown in function sym2(), the main idea of getting the result from sym2(a1,a2) can be divided into two steps: (1). for every elements in array a1[], if a1[j] is not in array a2[] and a1[j] is not in the result array syms[], then a1[j] is pushed to the result array. (!isin(a1[j],syms)can prevent repeating numbers in a1[], such as sym2 ([1,1],[3]) can return [1,3] instead of [1,1,3]. after a1-a2 is done, the second step a2-a1 is performed the same way (2).for every elements in array a2[], if a2[l] is not in array a1[] and a2[l] is not in the result array syms[], then a2[l] is pushed to the result array.
function sym() take a list of arrays, first, we can save all arrays from the arguments to a variable, like arg[array1,array2,array3], and use Array.reduce() function. for example,if arg contains [a1,a2,a3] arg.reduce(function(a,b){return sym2(a,b)}); is executed like following:
syms2(a1,a2)
syms2(syms2(a1,a2),a3)
all code :
function isin(num,arra)
{
for (var i=0; i<arra.length; i++)
if (num == arra[i]){return true;}
return false;
}
function sym2(a1,a2)
{
var j,l;
var syms = [];
for ( j=0; j<a1.length; j++){
if(!isin(a1[j], a2)&&!isin(a1[j],syms))
syms.push(a1[j]);
}
for ( l=0; l<a2.length; l++){
if(!isin(a2[l], a1)&&!isin(a2[l],syms))
syms.push(a2[l]);
}
return syms;
}
function sym(){
var arg=[];
for(var o = 0; o<arguments.length;o++)
arg.push(arguments[o]);
return arg.reduce(function(a,b){
return sym2(a,b);
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1], but it returns [1, 2, 3, 1, 2, 3]. What is wrong with this code?
function destroyer(arr) {
// Remove all the values
var arg_num = arguments.length;
var new_arr = arguments[0].filter(function(a){
for (var i = 1; i < arg_num; i++){
if (a === arguments[i]) a = false;
}
return a;
});
return new_arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
argument is used to get the list of arguments of current function. While performing filter you used argument, it gives argument of filter method. it differ from the destroyer method argument.
So store the destroyer method argument in one variable.
Try this code.
function destroyer(arr) {
// Remove all the values
var args = arguments;
var arg_num = args.length;
var flag;
var new_arr = arguments[0].filter(function (a) {
flag = false;
for (var i = 1; i < arg_num; i++) {
if (a === args[i]) {
flag = true;
break;
};
}
if (flag)
return false;
else
return true;
});
return new_arr;
}
console.log(destroyer([0, 2, 3, 0, 2, 3], 0, 3));
Hope this will help you.
You can instead use difference function from lodash library. It's a well tested and widely used utility library.
var _ = require('lodash');
var result = _.difference([1, 2, 3, 1, 2, 3], [2, 3])); // returns [1, 1]
The problem is that the arguments keyword is usually bound to the current function, which in this case is the anonymous function used in filter.
ES6 allows to fix this easily by introducing arrow functions, which don't bind arguments.
(function destroyer(arr) {
var arg_num = arguments.length;
return arguments[0].filter(a => {
for (var i = 1; i < arg_num; i++){
if (a === arguments[i]) return false;
}
return true;
});
})([1, 2, 3, 1, 2, 3], 2, 3); // [1, 1]
However, note this function has cost n m where n is the number of elements in the array and m is the number of additional arguments. But could be better.
For example, if the additional arguments will always be numbers, you can sort them, and then use dichotomic searches. This will cost n lg(m).
Another approach would be using a hash table. It will still cost n m on the worst case, but only n on average.
If you don't want to implement that manually, you can use a ES6 set. Its specific cost will be implementation dependent, but is required to be sublinear on average.
(function destroyer(arr, ...args) {
var s = new Set(args);
return arr.filter(a => !s.has(a));
})([1, 2, 3, 1, 2, 3], 2, 3); // [1, 1]