Luca
Luca

Reputation: 433

Group and summarize json data to new json object

I am using angularJS and have a JSON object from an API response which looks like the following:

var data = [
  {"group": "red", "state": "running"},
  {"group": "red", "state": "closed"},
  {"group": "red", "state": "closed"},
  {"group": "blue", "state": "running"},
  {"group": "blue", "state": "running"}
];

I would like to parse this object inside a javascript function to get the following result:

var sumdata = [
  {"group": "red", "running": 1, "closed": 2, "summary": 3},
  {"group": "blue", "running": 2, "closed": 0, "summary": 2}
];

So, I have to group the first property called "group", then count how many objects in this group are in running state, closed state and also summarize the count of objects.

(Note: I would not like to use extra javascript libraries like LINQ.js )

Could yo help me please?

I tried the following, which is missing the group by and have no idea how to put that into this function:

var getSum = function (data) {

    if (!data) {

        $scope.data = [];
    }
    else {

        for (var i = 0; i < data.length; i++) {

            var group = data[i][0];
            var status = data[i][1];

            status = (status ? status.Name : "").toUpperCase();

            var running = 0;
            var closed = 0;

            switch (status) {

                case "RUNNING":
                    running++;
                    break;

                case "CLOSED":
                    closed++;
                    break;

                default:
                    break;
            }
            var summary = running + closed;        
            $scope.dataSum.push({ "group": group, "running": running, "closed": closed, "summary": summary});
        }
    }

};

Upvotes: 2

Views: 3586

Answers (3)

Pavel Zlatanov
Pavel Zlatanov

Reputation: 37

The below snipped works for any number of fields in the data array. You only give the name of the field you want to group by. it is better than other examples in the way that it will work for any kind of data not only named like you suggested. Hope it help.

(function(){
        var data = [
                        { "group": "red", "state": "running" },
                        { "group": "red", "state": "closed" },
                        { "group": "red", "state": "closed" },
                        { "group": "blue", "state": "running" },
                        { "group": "blue", "state": "running" },
                        { "group": "blue", "state": "asd", "value":"33" },
                        { "group": "blue", "state": "asd1", "value":"33" },
                        { "group": "red", "state": "asd", "value":"33" }
        ],
        grouped = function (array) {
            var r = [];
            var groupFieldName = "group";

            array.forEach(function (a) {
                var self = this;
                if (!self[a[groupFieldName]]) {
                    var tempObj = {
                        group: a[groupFieldName]
                    };
                    self[a[groupFieldName]] = tempObj;
                    r.push(self[a[groupFieldName]]);
                }
                var keys = Object.keys(a);
                keys.forEach(function(key){
                    if(key != groupFieldName){
                        if(self[a[groupFieldName]][a[key]] == undefined){
                            self[a[groupFieldName]][a[key]] = 1;
                        }else{
                            self[a[groupFieldName]][a[key]]++;
                        }
                    }
                });
            }, Object.create(null));
            return r;
        }(data);
        console.log(JSON.stringify(grouped));

})()

Upvotes: 0

Krzysztof Safjanowski
Krzysztof Safjanowski

Reputation: 7438

With the LINQ power it will look something like that:

var data = [{
  "group": "red",
  "state": "running"
}, {
  "group": "red",
  "state": "closed"
}, {
  "group": "red",
  "state": "closed"
}, {
  "group": "blue",
  "state": "running"
}, {
  "group": "blue",
  "state": "running"
}];


var result = Enumerable.From(data).GroupBy('$.group', null, function(key, group) {
  return {
    group: key,
    running: group.Where(function(value) {
      return value.state == 'running'
    }).Count(),
    closed: group.Where(function(value) {
      return value.state == 'closed'
    }).Count(),
    summary: group.Where(function(value) {
      return value.state == 'running' || value.state == 'closed'
    }).Count()
  }
}).ToArray()

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386654

This is a proposal with a temporary object and an Array#forEach loop in plain Javascript.

var data = [{ "group": "red", "state": "running" }, { "group": "red", "state": "closed" }, { "group": "red", "state": "closed" }, { "group": "blue", "state": "running" }, { "group": "blue", "state": "running" }],
    grouped = function (array) {
        var r = [];
        array.forEach(function (a) {
            if (!this[a.group]) {
                this[a.group] = { group: a.group, running: 0, closed: 0, summary: 0 };
                r.push(this[a.group]);
            }
            this[a.group][a.state]++;
            this[a.group].summary++;
        }, Object.create(null));
        return r;
    }(data);

document.write('<pre>' + JSON.stringify(grouped, 0, 4) + '</pre>');

Upvotes: 3

Related Questions