Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using underscore js reduce

How does underscorejs reduce work?

It's simple to get _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); (the result is 6).

But how do the other optional parameters work? In the docs it says:

Memo is the initial state of the reduction, and each successive step of it should be returned by iterator. The iterator is passed four arguments: the memo, then the value and index (or key) of the iteration, and finally a reference to the entire list."

But I don't understand. I tried to use reduce for the following problem, and I couldn't figure it out:

var input = [{"score": 2, "name": "Jon", "venue": "A"}, {"score": 3, "name": "Jeff", "venue":"A"}, {"score": 4, "name": "Jon", "venue":"B"}, {"score": 4, "name": "Jeff", "venue":"B"}];

var output = [{"score": 6, "name":"Jon", "venue": ["A", "B"]}, {"score": 7, "name":"Jeff", "venue": ["A", "B"]}];

How can I get as output using _reduce for input? And it will really helpful how it works inside reduce.

like image 305
arnold Avatar asked Dec 16 '22 07:12

arnold


2 Answers

Reduce takes a list of values, and reduces it to a single value. What you are trying is not just reduce. You are trying to first group (by name) and then reduce each group. A possible implementation would be something like this, where you first group, and then map each group to a reduce operation that accumulates the score and appends the venue.

var input = [
    {"score": 2, "name": "Jon", "venue": "A"}, 
    {"score": 3, "name": "Jeff", "venue":"A"}, 
    {"score": 4, "name": "Jon", "venue":"B"}, 
    {"score": 4, "name": "Jeff", "venue":"B"}];

var output = _.map(_.groupBy(input, "name"), function(group, name) {
    return _.reduce(group, function(memo, elem) { 
            memo.score += elem.score;
            memo.venue.push(elem.venue);
            return memo;
        },
        { name: name, score: 0, venue: [] });
});
like image 158
Alberto Avatar answered Jan 10 '23 20:01

Alberto


Instead of reduce, try using plain and simple each in this way:

_.each admits a third parameter for a context. So, for example:

var input = ["Alice", "Bob", "Charlie"];
var context = {};

_.each(input, function(o,i) { this[i] = o; }, context);

console.log(context) //=> {1: "Alice", 2: "Bob", 3: "Charlie"}

Ruby has a new method call each_with_object similar to reduce for that exact pattern, where the memo is not necessarily the value return (in fact, my function is not returning anything!); but underscore simplifies its API design simply admitting a context for the function as the third parameter.

You can use reduce, but you would need to return the memo each time, making it a bit less elegant IMHO.

like image 39
Serabe Avatar answered Jan 10 '23 20:01

Serabe