RedGiant
RedGiant

Reputation: 4748

Grouping a nested array

Fiddle Example

I have an array generated by nest method in d3.js Can anyone suggest a javascript/jQuery way of grouping the objects in the values property by category?

var data = [
  {
    "key": "0",
    "values": [
      {
        "category": "phone",
        "brand": "Sony",
        "brand_id": "0",
        "name": "item A",
        "id": "551",
        "point": "600"
      },
      {
        "category": "software",
        "brand": "Sony",
        "brand_id": "0",
        "name": "item D",
        "id": "51",
        "point": "800"
      },
      {
        "category": "phone",
        "brand": "Sony",
        "brand_id": "0",
        "name": "item E",
        "id": "52",
        "point": "1800"
      }
    ]
  },
  {
    "key": "0",
    "values": [
      {
        "category": "software",
        "brand": "Microsoft",
        "brand_id": "1",
        "name": "item B",
        "id": "54",
        "point": "800"
      },
      {
        "category": "phone",
        "brand": "Microsoft",
        "brand_id": "1",
        "name": "item B",
        "id": "60",
        "point": "200"
      },
      {
        "category": "phone",
        "brand": "Microsoft",
        "brand_id": "1",
        "name": "item T",
        "id": "30",
        "point": "600"
      },
      {
        "category": "software",
        "brand": "Microsoft",
        "brand_id": "1",
        "name": "item N",
        "id": "90",
        "point": "500"
      }
    ]
  }
];

Here's a desired result:

[
  {
    "key": "0",
    "values": [
      {
        "phone": [
          {
            "category": "phone",
            "brand": "Sony",
            "brand_id": "0",
            "name": "item A",
            "id": "551",
            "point": "600"
          },
          {
            "category": "phone",
            "brand": "Sony",
            "brand_id": "0",
            "name": "item E",
            "id": "52",
            "point": "1800"
          }
        ],
        "software": [
          {
            "category": "software",
            "brand": "Sony",
            "brand_id": "0",
            "name": "item D",
            "id": "51",
            "point": "800"
          }
        ]
      }
    ]
  },
  {
    "key": "0",
    "values": [
      {
        "phone": [
          {
            "category": "phone",
            "brand": "Microsoft",
            "brand_id": "0",
            "name": "item B",
            "id": "80",
            "point": "54"
          },
          {
            "category": "phone",
            "brand": "Microsoft",
            "brand_id": "0",
            "name": "item D",
            "id": "52",
            "point": "1800"
          }
        ],
        "software": [
          {
            "category": "software",
            "brand": "Microsoft",
            "brand_id": "0",
            "name": "item G",
            "id": "41",
            "point": "800"
          },
          {
            "category": "software",
            "brand": "Microsoft",
            "brand_id": "0",
            "name": "item L",
            "id": "42",
            "point": "900"
          }
        ]
      }
    ]
  }
]

The following code doesn't work. I guess it's because grouped[t.category] = [] is defined in every loop. The previous item would be overwritten by the last one. If I didn't defined it, I would get a grouped[t.category] undefined error:

grouped = {};
data.forEach(function(d){
  d.values.map(function(t){ 
     grouped[t.category] = [];       
     grouped[t.category].push({name:t.name,tid:t.id,point:parseInt(t.point)});
   })
})

Upvotes: 2

Views: 4572

Answers (4)

Jerry Ni
Jerry Ni

Reputation: 531

I'm familiar with underscore.js:

var desireResult = _.map(data, function(obj){
    obj.values = _.groupBy(obj.values, 'category');
    return obj;
});

Hope it will help you !

Upvotes: 1

emk
emk

Reputation: 185

You can solve it this way using lodash or similar library

_.map(data, function(x){
  return _.assign({}, x, {values: _.groupBy(x.values, 'category')})
})

Fiddle

Upvotes: 3

azaviruha
azaviruha

Reputation: 897

You can try this: jsfiddle

var result = data.map(function ( record ) {
    return {
        key:    record.key,
        values: [ groupBy( 'category', record.values ) ]
    };
})

function groupBy ( key, arr ) {
    var groups = {};
    arr.forEach(function ( el ) {
        var keyVal = el[ key ];
        if ( !keyVal ) return;

        if ( groups[ keyVal ] )
            groups[ keyVal ].push( el );
        else
            groups[ keyVal ] = [ el ];
    });
    return groups;
}

Upvotes: 1

Oleksandr T.
Oleksandr T.

Reputation: 77482

Try this

var grouped;

data.forEach(function(d) {
    grouped = {};

    d.values.forEach(function(t) {
         if (!grouped[t.category]) {
             grouped[t.category] = [];
         }

         grouped[t.category].push({
             name:  t.name,
             tid:   t.id, 
             point: parseInt(t.point)
         });
     })

    d.values = grouped;
});

Example

Upvotes: 2

Related Questions