1

I am trying to recreate the underscore js function difference using reduce. Difference takes in multiple arrays and returns all values that are similiar to the first array. so [1,2],[2,3],[1,3] should spit out [1,2,2,1].

I was thinking of looping through each of my subarray(rest) and if the value of my sub elements has an index in my first array then I will push that element onto my accumulator value(which is an empty array).

Some reason I do not get my intended output where I was expecting [1,2,3,2,1,2]. instead I am getting [ [ 1, 2 ], [ 2, 4 ], [ 1, 2 ] ]. Can anyone help me with this rewrite using reduce. Thanks.

function difference(arrays){
var arrayed=Array.prototype.slice.call(arguments);
var first=arrayed[0];
var rest=arrayed.slice(1);

return reduce(first,function(acc,cur){
  forEach(rest,function(sub){
    if (sub.indexOf(cur)>-1){
      acc.push(sub);
    }});
    return acc;
  },[]);
}

console.log(difference([1,2,3],[2,4],[1,2],[4,5]));

i know the way im calling forEach is different but it is because my own version of forEach accepts two arguments.

learninjs
  • 89
  • 1
  • 1
  • 7
  • Your explanation of the algorithm is unclear. Should the result be the values of the first array, then repeated values from subsequent arrays? – RobG May 05 '17 at 00:13

3 Answers3

1

Here's a solution :

function difference(arrays){
  var arrayed = Array.prototype.slice.call(arguments);
  var first = arrayed.splice(0,1)[0]; // edit, thanks robG
  var tmp = [];

  return arrayed.reduce(function(acc, arr) {
    return acc.concat(arr.filter(function(el) {
      return first.includes(el);
    }));
  }, first);
}

console.log(difference([1,2,3],[2,4],[1,2],[4,5]));

Use the javascript reduce method on the 'rest' array, makes the first array be the default value of the accumulator, filter the arrays with the first one and concat the result to your accumulator.

Hope it helps,
best regards

boehm_s
  • 5,254
  • 4
  • 30
  • 44
1

Could try this

function difference(arrays){
  var arrayed=Array.prototype.slice.call(arguments);
  var first=arrayed[0];
  var rest=arrayed.slice(1);

  return first.concat(rest.reduce(function(acc, cur, curIndex, array){
    first.forEach(function(eachEle){
      if(cur.indexOf(eachEle) > -1 )
        acc.push(cur[cur.indexOf(eachEle)]);
    });
    return acc;
  }, []));
}

console.log(difference([1,2,3],[2,4],[1,2],[4,5]));
Phagun Baya
  • 2,127
  • 1
  • 18
  • 27
1

As for your previous question, you need to call array methods on arrays, not pass them as parameters so not

return reduce(first,function(acc,cur){...})

but

return first.reduce(function(acc,cur){...});

In your function:

var first=arrayed[0];
var rest=arrayed.slice(1);

can be replaced with one step using splice:

var first = arrayed.splice(0, 1)

and use arrayed instead of rest. But there's no need for that anyway. If no accumulator is provided, then the first value is used, so (with some renaming of variables):

function difference(){
  var args = Array.prototype.slice.call(arguments);

  return args.reduce(function(acc, cur){
    cur.forEach(function(value){
      if (acc.includes(value)){
        acc.push(value);
      }
    });
    return acc;
  });
}

console.log(difference([1,2,3],[2,4],[1,2],[4,5]));
Community
  • 1
  • 1
RobG
  • 142,382
  • 31
  • 172
  • 209