2

I have an array of items that contains several properties. One of the properties is an array of tags. What is the best way of getting all the tags used in those items and ordered by the number of times that those tags are being used on those items? I've been trying to look to underscore js but not getting the expected results.

return _.groupBy(items, 'tags');

Example of my data:

item1
 - itemName: item1
 - tags(array): tag1, tag2

item2
 - itemName: item2
 - tags(array): tag1, tag3

so I'm trying to get something like {tag1, 2}{tag2, 1}{tag3, 1}

Update: My tag contains a ID and a name. I'm trying to group by those IDs

Snapper
  • 686
  • 1
  • 13
  • 29
  • What is `{tag1, 2}{tag2, 1}{tag3, 1}` supposed to be? It's not a valid array or object. – Phil May 02 '16 at 05:08
  • @Phil You are right. Just trying to get a way of getting how many times a tag is being used. I've edited my question. – Snapper May 02 '16 at 05:17

3 Answers3

4

You can do this simply using a reduce operation. For example

var items = [{
  itemName: 'item1',
  tags: [
    {id: 'tag1', name: 'Tag 1'},
    {id: 'tag2', name: 'Tag 2'}
  ]
}, {
  itemName: 'item2',
  tags: [
    {id: 'tag1', name: 'Tag 1'},
    {id: 'tag3', name: 'Tag 3'}
  ]
}];

var tags = items.reduce((tags, item) => {
  item.tags.forEach(tag => {
    tags[tag.id] = tags[tag.id] || 0;
    tags[tag.id]++;
  });
  return tags;
}, {});

document.write('<pre>' + JSON.stringify(tags, null, '  ') + '</pre>');
Phil
  • 157,677
  • 23
  • 242
  • 245
  • Tried to implement this code but I'm getting Object {[object Object]: 3} Is this expected? I'm not sure how to get the count per tag – Snapper May 02 '16 at 05:00
  • 1
    @Snapper How are you *"getting"* that (hopefully not via `alert()`)? What **exactly** does your `items` array look like? – Phil May 02 '16 at 05:06
  • Sorry about that. I realized that my tags array is slightly different from what I initially posted. Will update – Snapper May 02 '16 at 05:12
3

Map all tag arrays into a single array, and then countBy

var tags = _.flatten(_.map(items,d=>d.tags))
tags = _.countBy(tags)

Using underscores chain utility

var tags = _.chain(items).map(d=>d.tags).flatten().countBy().value();
Eric Guan
  • 15,474
  • 8
  • 50
  • 61
  • I think I'm doing something wrong. Implemented this and got the same result as in the other answer below @Phil. Object {[object Object]: 3} How can I get then get the tags and how often they are being used? – Snapper May 02 '16 at 05:02
  • 2
    Your data structure must differ from the ones me and Phil used, b/c i checked his answer out of curiousity. Look at my jsfiddle and see if we're using the same data https://jsfiddle.net/guanzo/ppfLwhyx/1/ – Eric Guan May 02 '16 at 05:05
  • Thanks for the code @Eric Guan, made me realize that my structure is not exactly how I initially posted. Will update. – Snapper May 02 '16 at 05:13
  • Beautiful answer. I think that `countBy` should be `countBy('id')` and that mapping could be replaced with `pluck('tags')`. – Gruff Bunny May 02 '16 at 07:49
0

You may try this too:

var tagGroup =
  items.reduce(function(p, c){
      c.tags.map(function(tag){     
        p[tag] = p[tag] || {count:0};         
        p[tag].count++;
        return p;
      });

      return p;
  }, {});
Dhananjaya Kuppu
  • 1,322
  • 9
  • 10