user1526570 user1526570 - 6 months ago 12
Javascript Question

How to group data with similar keys?

I have this data from CSV:

Group Profession Status Count
6 Fisherman Offer Accepted 1
6 Fisherman All 1
7 Fisherman Offer Accepted 1
7 Fisherman All 1
8 Banker Onboard 2
8 Banker All 2
8 Cook Onboard 4
8 Cook All 4
8 Developer Onboard 2
8 Developer All 2
9 Banker Onboard 2
9 Banker Offer Accepted 1
9 Banker All 3


Which I need to return as a JSON array:

"Fisherman" : {
6 : {
"Offer Accepted" : 1,
"All" : 1
},
7 : {
"Offer Accepted" : 1,
"All" : 1
}
},
"Banker" : {
8 : {
"Onboard" : 2,
"All" : 2
},
9 : {
"Onboard" : 2,
"Offer Accepted" : 1,
"All" : 3
}
},
....so on


So far, what I did was I got all the unique Profession and Group.

Then I looped through all the data and compared if there's a match for Profession AND Group.

for(var d in data) {
var json = [];
for(var p in profession) {
for(var g in group) {
if(data[d]["Profession"] == profession[p] && data[d]["Group"] == group[g]) {
json.push({data[d]["Status"] : data[d]["Count"]});
// put 'json' variable in JSON array with key group?
}
}
}
}


If there is a match, I created an array wherein I pushed the Status and Count.

But I really don't know how to proceed from there.

Thank you for your help!

Answer

Suppose data is an array with objects like,

{ Group: 6, Profession: 'Fisherman', Status: 'Offer Accepted', Count: 1 }

then you could use the following

var order = ['Profession', 'Group', 'Status'],
    object = {};

data.forEach(function (d) {
    order.reduce(function (r, a) {
        r[d[a]] = r[d[a]] || {};
        return r[d[a]];
    }, object).Count = d.Count;
});

How it works:

d is an object with the structure like above. oder is an array with keys in the wanted order for the result object. (I renamed json to object, because JSON is a string with a special formatting and not an object, like here necessary.)

For an assignment of count, it is necessary to know the path to the property. This is granted with iterating over the order for the keys of the actual object d.

r[d[a]] = r[d[a]] || {};

This d[a] is taken for a check if the property exits and if not to assign an empty object.

At the end of the callback, the reference to the last object r[d[a]] is returned.

At last, a new property Count is assinged with the value of d.Count

object                       a          d[a]           return value
---------------------------- ---------- -------------- ------------
{}                           Profession Fisherman      {}
                /--------------------------------------/            (same reference)
{ "Fisherman": {} }          Group      6              {}
                       /-------------------------------/            (same reference)
{ "Fisherman": { "6": {} } } Status     Offer Accepted {}

object after first loop of data

{
    "Fisherman": {
        "6": {
            "Offer Accepted": {
                "Count": 1
            }
        }
    }
}

Roundup: reduce returns something, which is highly controllable.

Comments