Underscore.js groupBy multiple values

前端 未结 9 1436
渐次进展
渐次进展 2020-12-01 05:03

Using Underscore.js, I\'m trying to group a list of items multiple times, ie

Group by SIZE then for each SIZE, group by CATEGORY...

http://jsfiddle.net/ricky

相关标签:
9条回答
  • 2020-12-01 05:03

    How about this rather simple hack?

    console.log(_.groupBy(getProperties(), function(record){
        return (record.size+record.category);
    }));
    
    0 讨论(0)
  • 2020-12-01 05:06

    An example with lodash and mixin

    _.mixin({
    'groupByMulti': function (collection, keys) {
    if (!keys.length) {
     return collection;
     } else {
      return _.mapValues(_.groupBy(collection,_.first(keys)),function(values) {
        return _.groupByMulti(values, _.rest(keys));
      });
    }
    }
    });    
    
    0 讨论(0)
  • 2020-12-01 05:09

    Check out this underscore extension: Underscore.Nest, by Irene Ros.

    This extension's output will be slightly different from what you specify, but the module is only about 100 lines of code, so you should be able to scan to get direction.

    0 讨论(0)
  • 2020-12-01 05:13

    This is a great use case for the reduce phase of map-reduce. It's not going to be as visually elegant as the multi-group function (you can't just pass in an array of keys to group on), but overall this pattern gives you more flexibility to transform your data. EXAMPLE

    var grouped = _.reduce(
        properties, 
        function(buckets, property) {
            // Find the correct bucket for the property
            var bucket = _.findWhere(buckets, {size: property.size, category: property.category});
    
            // Create a new bucket if needed.
            if (!bucket) {
                bucket = {
                    size: property.size, 
                    category: property.category, 
                    items: []
                };
                buckets.push(bucket);
            }
    
            // Add the property to the correct bucket
            bucket.items.push(property);
            return buckets;
        }, 
        [] // The starting buckets
    );
    
    console.log(grouped)
    

    But if you just want it in an underscore mixin, here's my stab at it:

    _.mixin({
    'groupAndSort': function (items, sortList) {
        var grouped = _.reduce(
            items,
            function (buckets, item) {
                var searchCriteria = {};
                _.each(sortList, function (searchProperty) { searchCriteria[searchProperty] = item[searchProperty]; });
                var bucket = _.findWhere(buckets, searchCriteria);
    
                if (!bucket) {
                    bucket = {};
                    _.each(sortList, function (property) { bucket[property] = item[property]; });
                    bucket._items = [];
                    buckets.push(bucket);
                }
    
                bucket._items.push(item);
                return buckets;
            },
            [] // Initial buckets
        );
    
        grouped.sort(function (x, y) {
            for (var i in sortList) {
                var property = sortList[i];
                if (x[property] != y[property])
                    return x[property] > y[property] ? 1 : -1;
            }
            return 0;
        });
    
        return _.map(grouped, function (group) {
            var toReturn = { key: {}, value: group.__items };
            _.each(sortList, function (searchProperty) { toReturn.key[searchProperty] = group[searchProperty]; });
            return toReturn;
        });
    });
    
    0 讨论(0)
  • 2020-12-01 05:13

    The improvements by joyrexus on bergi's method don't take advantage of the underscore/lodash mixin system. Here it is as a mixin:

    _.mixin({
      nest: function (collection, keys) {
        if (!keys.length) {
          return collection;
        } else {
          return _(collection).groupBy(keys[0]).mapValues(function(values) {
            return _.nest(values, keys.slice(1));
          }).value();
        }
      }
    });
    
    0 讨论(0)
  • 2020-12-01 05:15

    Here is an easy to understand function.

    function mixin(list, properties){
    
        function grouper(i, list){
    
            if(i < properties.length){
                var group = _.groupBy(list, function(item){
                    var value = item[properties[i]];
                    delete item[properties[i]];
                    return value;
                });
    
                _.keys(group).forEach(function(key){
                    group[key] = grouper(i+1, group[key]);
                });
                return group;
            }else{
                return list;
            }
        }
    
        return grouper(0, list);
    
    }
    
    0 讨论(0)
提交回复
热议问题