David J.
David J.

Reputation: 1913

attempting a code challenge in js, getting unexpected results --

The goal is to create a function called destroyer that filters all arguments after an initial array argument out of the array.

I'm not very good at functional programming yet so my answer doesn't work, but I'm getting some fish results that I don't understand. Here's my function:

function destroyer(arr) {
  var count = 1;
  var result = arr;
  return result.reduce(function(val){
    if (count < arguments.length){
      console.log('count is ' + count);
      console.log("filtering " + arguments[count]);
       result = result.filter(function(val){val!=arguments[count]});
       count += 1;
       return result;

    }
    else {
      return result;
    }

  }, count);
}

Given destroyer([1, 2, 3, 1, 2, 3], 2, 3);, this evaluates to [], whereas it should return [1, 1]

My console logs the following:

"count is 1"
"filtering 1"
"count is 2"
"filtering 1"
"count is 3"
"filtering 1,2,3,1,2,3"

What I don't understand:

  1. Why is the conditional even evaluated when count is 3? My if statement has < arguments.length(which is 3), not <=
  2. Given the input destroyer([1, 2, 3, 1, 2, 3], 2, 3);, why isn't arguments[count] (which should be limited from 1 - 2) returning the console log "filtering 2" ... "filtering 3" ... (and nothing else... I have no clue why the last log is coming up).
  3. About that last log... is it being returned because of arguments[3]? Shouldn't that come up undefined?

Upvotes: 1

Views: 72

Answers (4)

Andre Nel
Andre Nel

Reputation: 442

My solution:

function removeAll(_arr, _rem)
{
  while(_arr.indexOf(_rem) !== -1)
  {
    var i = _arr.indexOf(_rem);
    _arr.splice(i,1);
  }
  return _arr;
}

function destroyer(_arr, _remA, _remB)
{
  var arr = removeAll(_arr, _remA);
  arr = removeAll(arr, _remB);
  return arr;
}

var arr = destroyer([1,2,3,1,2,3], 2, 3);

console.log(arr);

document.getElementById('divOut').innerHTML = 'destroyer([1,2,3,1,2,3], 2, 3) -> ' + JSON.stringify(arr);
<div id='divOut'></div>

though I would prefer to send an array of what to 'destroy' (/remove) as follows:

    function removeAll(_arr, _rem)
    {
      while(_arr.indexOf(_rem) !== -1)
      {
        var i = _arr.indexOf(_rem);
        _arr.splice(i,1);
      }
      return _arr;
    }

    function destroyer(_arr, _remArray)
    {
      var arr = _arr.splice(0); // clone array
      for(var c = 0, length = _remArray.length; c < length; c++)
      {
        arr = removeAll(arr, _remArray[c]);
      }
      return arr;
    }

    var arr = destroyer([1,2,3,4,5,1,2,3,4,5], [2,3,5]);

    console.log(arr);

    document.getElementById('divOut').innerHTML = 'destroyer([1,2,3,4,5,1,2,3,4,5], [2,3,5]) -> ' + JSON.stringify(arr);
<div id="divOut"></div>

Upvotes: -1

nashcheez
nashcheez

Reputation: 5183

The issue here is that you have a nested function inside a function and the value of the arguments object will be different inside both the closures.

I would suggest store each of them in a local variable and use instead of repeating the usage of arguments.

I did a dry run of your code in the console, and will attach a screenshot of the values of your arguments object and other variables for the first run for your understanding.

enter image description here

Notice how the value of arguments changes before and after the return result.reduce(function(val)) { line.

Upvotes: 2

Himanshu Tanwar
Himanshu Tanwar

Reputation: 906

    function destroyer(arr) {
      var count = 1;
      var result = arr;
      var args = arguments; //keep reference of original passed arguments;
      return result.reduce(function(val){
          //use args not arguments because here arguments 
          //will refer to the arguments of the inner function
        if (count < args.length){
          console.log('count is ' + count);
          console.log("filtering " + args[count]);
           result = result.filter(function(val){return val!=args[count]});
           count += 1;
           return result;

        }
        else {
          return result;
        }

      }, count);
    }

    destroyer([1, 2, 3, 1, 2, 3], 2, 3);

Upvotes: 1

lapkritinis
lapkritinis

Reputation: 2814

I will try to help you a bit. 1) arguments are 4, not 3. Add

  console.log(arguments);
  console.log(arguments.length);

And you will see it yourself. First argument is acumulator for function reduce. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

Upvotes: 1

Related Questions