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;
}
Related
I need to create a function for filter and it must have 2 choices.
inBetween(a, b) - which will return array between a and b
inArray([...]) - which will return an array of items that match with filtering array.
Something like this:
let arr = [1, 2, 3, 4, 5, 6, 7];
console.log( arr.filter(f(inBetween(3, 6))) ); // 3,4,5,6
console.log( arr.filter(f(inArray([1, 2, 10]))) ); // 1,2
I tried this function:
function f(item) {
let result = [];
function inBetween(from, to){
if (item >= from && item <= to){
result.push(item);
}
}
function inArray(array){
if (array.indexOf(item) >= 0){
result.push(item);
}
}
return result;
}
But I don't know how to attach my function into filter. It gives this error:
console.log( arr.filter(f(inBetween(3, 6))) ); // 3,4,5,6
ReferenceError: inBetween is not defined
Is it somehow possible?
array.filter() requires a function. If you want to pre-bind some parameters, you'll need a function that returns a function. In this case, both inBetween and inArray should return functions.
So it should be:
let arr = [1, 2, 3, 4, 5, 6, 7];
function inBetween(min, max) {
return function(value) {
// When this is called by array.filter(), it can use min and max.
return min <= value && value <= max
}
}
function inArray(array) {
return function(value) {
// When this is called by array.filter(), it can use array.
return array.includes(value)
}
}
console.log( arr.filter(inBetween(3, 6)) )
console.log( arr.filter(inArray([1, 2, 10])) )
In this case, min, max, and array close over the returned function such that when array.filter() calls the returned function, it has access to those values.
Your inArray() functionality is already implemented by the native array.includes().
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)));
function destroyer(arr) {
// Remove all the values
var toFilter;
var toFrom;
for(var i=0;i<arguments.length;i++) {
if (typeof arguments[i]=="object") {
toFilter = arguments[i];
} else {
toFrom = arguments[i];
}
}
var result = toFilter.filter(function(value,index,array) {
if(value===toFrom) {
return true;
}
return result;
});
console.log(result);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); // it should return [1,1]
It's almost been more than one week that i'm trying to solve this algorithm. In this task we need to remove the arguments value present in the initial array, they have mentioned to solve this by using arguments and filter method. Well i know what filter and arguments does in Javascript and i solved the previous algorithm using filter method and i read about arguments and it's use but never used it before. Every time i did something using these two it gave me a blank array. Please can anyone help me how can we do this using filter and arguments ?
Just my idea, you can modify it the way you want:
function isValid() {
return value != 2 && value != 3;
}
var arr = [1, 2, 3, 1, 2, 3];
arr.filter(isValid); //It should return [1,1];
What you need now is to get 2 and 3 value from arguments object and change isValid function.
There are several problems, let's list them one by one:
You overwrite toFrom, so instead of your intention to get ALL non-objects (i.e. 2 & 3), you only get the last non-object (i.e. 3)
In filter(), return true means "Keep this element in the list", and you return true if the value is equal to toFrom = 3
The verb solve does not work with the noun algorithm. Because algorithm is the way to solve a problem
I didn't try but I guess your code will output [3,3], so if you want to output [1,1], try following modified code based on your version:
function destroyer(arr) {
// Remove all the values
var toFilter;
var toFrom = [];
for(var i=0;i<arguments.length;i++) {
if (typeof arguments[i]=="object") {
toFilter = arguments[i];
} else {
// maintain a list of ALL non-objects which to be filtered
toFrom.push(arguments[i]);
}
}
var result = toFilter.filter(function(value,index,array) {
if(toFrom.indexOf(value) != -1) {
// If element is in the toFrom list, DO NOT keep it
return false;
}
return true;
});
console.log(result);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); // it should return
or you may try my version :)
function destroyer(arr) {
// Remove all the values
for(var i=0;i<arguments.length;i++) {
arr = arr.filter( x => x !== arguments[i]);
}
console.log(arr);
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); // it should return
What you can do is construct a lookup of the values that you want to remove from the array, and then filter the original array by returning values that do not exist in the lookup:
function destroyer(arr) {
var lookup = {};
// For each remaining argument, add it to the lookup.
for (var i = 0; i < arguments.length; i++) {
lookup[arguments[i]] = true;
}
// Filter the array and return a new array
// with elements that don't exist in the lookup.
return arr.filter(function(elem) {
return typeof lookup[elem] === 'undefined';
});
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3)); //it should return [1,1]
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);
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]