Regrouping JSON object

Posted on

Problem

I wrote a JavaScript source which regrouping by new key i.e. following JSON to the other:

{
    "items" : [
        {
            "company" : "A"
            , "name" : "Prod_A01" 
        }
        , {
            "company" : "A"
            , "name" : "Prod_A02"
        }
        , {
            "company" : "B"
            , "name" : "Prod_B01"
        }
    ]
}

to:

{
    "A" : [
        {
            "company" : "A"
            , "name" : "Prod_A01" 
        }
        , {
            "company" : "A"
            , "name" : "Prod_A02"
        }
    ]

    , "B" : [
        {
            "company" : "B"
            , "name" : "Prod_B01"
        }
    ]
}

And here is logic:

function regroup(collection, key){
    var novo_obj = {};
    var type = typeof collection;
    var keyGroup = [];

    getKeyGroup(collection, key, keyGroup);

    for(var i = 0; i < keyGroup.length; i++) {
        novo_obj[keyGroup[i]] = [];
        gatherElements(collection, key, keyGroup[i], novo_obj[keyGroup[i]]);
        //console.log(novo_obj);
    }
    console.log(JSON.stringify(novo_obj));
    return novo_obj;
}

function gatherElements(collection, key, value, arr){
    //console.log(collection);
    if(typeof collection == 'object'){
        var targetValue = collection[key];
        if(typeof targetValue != 'undefined' && targetValue == value){
            arr.push(collection);
        }else{
            for(var elem in collection){
                gatherElements(collection[elem], key, value, arr);
            }
        }
    }else if(typeof collection == 'array'){
        for(var i = 0; i < collection.length; i++) {
            getKeyGroup(collection[i], key, value, arr);
        }
    }
}

function getKeyGroup(collection, key, keygroup){
    var targetValue = '';
    if(typeof collection == 'object'){
        targetValue = collection[key];
        if(typeof targetValue != 'undefined'){
            keygroup.push(targetValue);
        }else{
            for(var elem in collection){
                getKeyGroup(collection[elem], key, keygroup);
            }
        }
    }else if(typeof collection == 'array'){
        console.log('isArr');
        for(var i = 0; i < collection.length; i++) {
            getKeyGroup(collection[i], key, keygroup);
        }
    }
    return keygroup;
}

function main(){
    var test = {
        items : [
            {
                company : "A"
                , name : "Prod_A01"
            }
            , {
                company : "A"
                , name : "Prod_A02"
            }
            , {
                company : "B"
                , name : "Prod_B01"
            }
        ]
    }
    regroup(test, "company");
}

However, I think looping every time does not look so good. I need to improve this source code.

Solution

I think you may be complicating things a lot. If I understand correctly you are basically after groupBy which you can find in lodash, or implement in a few lines of code:

function groupBy(coll, f) {
  return coll.reduce(function(acc, x) {
    var k = f(x);
    acc[k] = (acc[k] || []).concat(x);
    return acc;
  }, {});
}

var test = {
  items: [{
    company: "A", name: "Prod_A01"
  }, {
    company: "A", name: "Prod_A02"
  }, {
    company: "B", name: "Prod_B01"
  }]
};

var result = groupBy(test.items, function(x){return x.company});

JSON.stringify(result);
/*^
{
  "A": [
    {
      "company": "A",
      "name": "Prod_A01"
    },
    {
      "company": "A",
      "name": "Prod_A02"
    }
  ],
  "B": [
    {
      "company": "B",
      "name": "Prod_B01"
    }
  ]
}
*/

You can use this to group a collection (array of objects) by some property, test.items in this case. Also, I would leave the JSON part out of it, because it is irrelevant to the grouping algorithm.

Leave a Reply

Your email address will not be published. Required fields are marked *