5

I'm relatively new to underscore.js and I have an object coming in from a REST service which looks like this (I have typed it out by hand and assigned it to a var here):

var production = [
    {key: ["wind", "1"], value: 5},
    {key: ["wind", "2"], value: 9},
    {key: ["wind", "3"], value: 11},
    {key: ["wind", "4"], value: 7},
    {key: ["solar", "1"], value: 1},
    {key: ["solar", "2"], value: 1},
    {key: ["solar", "3"], value: 2},
    {key: ["solar", "4"], value: 3},
    {key: ["oil", "1"], value: 15},
    {key: ["oil", "2"], value: 16},
    {key: ["oil", "3"], value: 22},
    {key: ["oil", "4"], value: 23},
];

Then further down, I have some code that parses this object and creates arrays for the items like so:

var orderedProduction = _.chain(production)
      .groupBy(function (entity) {
            return entity.key[0];
      })
      .map(function (values) { 
            return _.map(values, function (entity2) {
                  return entity2.value;
            });
      })
      .value();

This gives the following results:

orderedProduction  = [
  [5, 9, 11, 7],
  [1, 1, 2, 3],
  [15, 16, 22, 23]
]

Which loses the keys (wind/solar/oil). And is used to draw a graph. I'm further able to check if some of these arrays meet a certain threshold like so:

var threshold = _.map(orderedProduction  , function(arr) {
    return _.max(arr) > 10;
});

My requirements have now changed and I now need to filter out these arrays by its total sum, while retaining the key.

What I would like to end up with an object like so:

orderedProduction  = {
      "wind": [5, 9, 11, 7],
      "solar": [1, 1, 2, 3],
      "oil": [15, 16, 22, 23]
    }

It would be great if the fix included a way to sum up the values of the array and remove those that do not total up to a certain amount. (i.e. exclude solar, if it does not add up to 10).

Here is a jsfiddle I created to test this all out on: http://jsfiddle.net/2mfjw3jk/


UPDATE: The solution I settled for was this:

var orderedProduction = _.chain(production)
    .groupBy(function (entity) {
        return entity.key[0];
    })
    .map(function (vals, key) {
        return [key, _.pluck(vals, 'value')]
    })
    .filter(function(arr) {
        var sum = 0;
        _.each(arr[1], function(num){
            sum += num;
        })
        return sum > 10;
    })
    .object()
    .value();

It also filters the values by a predetermined threshold (10 in this case).

3 Answers 3

7

You're almost there:

var orderedProduction = _.chain(production)
    .groupBy(function (entity) {
        return entity.key[0];
    })
    .map(function (vals, key) {
        return [key, _.pluck(vals, 'value')]
    })
    .object()
    .value();

returns

{ wind: [ 5, 9, 11, 7 ],
  solar: [ 1, 1, 2, 3 ],
  oil: [ 15, 16, 22, 23 ] }
Sign up to request clarification or add additional context in comments.

1 Comment

Awesome. I did manage it, using chain, pluck, uniq, object. But this solution is so much neater. Thanks very much.
2

You can simply use the map() function provided in javascript. The _.map() given is for backward compatibility. Anyways, here is the code :

var obj = {};
production.map(function(data) {
    if(data.key[0] in obj) {
        obj[data.key[0]] += data.value;
    } else {
        obj[data.key[0]] = 0;
        obj[data.key[0]] += data.value;
    }
});
console.log(obj);

So what is does is that it loops throught the production array. There, it checks whether the key(for example, 'key' is the key) is in the obj object or not. If it is there then it simply increments its value or else makes a new key and assigns it 0 and then increments it.

Not the most optimized code but it works nicely.

1 Comment

This is helpful, but I do not need the totals. I still need an array of values (i.e "oil": [15, 16, 22, 23])
1

This is probably not the best performing code, but it gets the job done using underscore.

Live Demo

var production = [
    {key: ["wind", "1"], value: 5},
    {key: ["wind", "2"], value: 9},
    {key: ["wind", "3"], value: 11},
    {key: ["wind", "4"], value: 7},
    {key: ["solar", "1"], value: 1},
    {key: ["solar", "2"], value: 1},
    {key: ["solar", "3"], value: 2},
    {key: ["solar", "4"], value: 3},
    {key: ["oil", "1"], value: 15},
    {key: ["oil", "2"], value: 16},
    {key: ["oil", "3"], value: 22},
    {key: ["oil", "4"], value: 23}
];

var orderedProduction =  _.chain(production)
    .groupBy(function (entity) {
        return entity.key[0];
    })
    .map(function(items, key){
        var returnVal = [key]; 
        var total = 0; 
        returnVal.push(_.map(items, function(obj){
            total += obj.value; 
            return obj.value; 
        })); 

        if(total > 10){
            return returnVal; 
        }

    })
    .filter(function(num) {
        return num !== undefined;
    })
    .object()
    .value();

console.log(production);
console.log(orderedProduction);

2 Comments

This is pretty close. It gives an array of objects and removes the solar object. What I wanted was an object with properties (wind/solar/oil) and each property has an array of numbers.
Ahh, not sure how I missed that. I know you've already got an answer, but I corrected this anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.