1

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);
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Nhan Nguyen
  • 197
  • 1
  • 9

3 Answers3

2

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.

balachandar
  • 825
  • 4
  • 13
  • 2
    Your function will not work when the value in array is `0`. You need to return true of false not the element. – jcubic Nov 28 '15 at 11:59
  • Try this https://jsfiddle.net/exj1zux7/2/ if the value is `0` and it's not the list to remove it will return that element from filter wich is falsy and it will not be on the list. – jcubic Nov 28 '15 at 12:10
  • @jcubic Yeah you correct, now I updated my code. Thanks for your information. – balachandar Nov 28 '15 at 12:22
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]
Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Note that ES6 sets compare using the [SameValueZero equality algorithm](http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero) instead of the [Strict Equality Comparison](http://www.ecma-international.org/ecma-262/6.0/#sec-strict-equality-comparison) used by `===`. They behave differently for `NaN`. – Oriol Nov 28 '15 at 13:22
1

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]
Kunal Kapadia
  • 3,223
  • 2
  • 28
  • 36