Underscore.js groupBy multiple values

2019-01-08 14:00发布

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/rickysullivan/WTtXP/1/

Ideally, I'd like to have a function or extend _.groupBy() so that you can throw an array at it with the paramaters to group by.

var multiGroup = ['size', 'category'];

Probably could just make a mixin...

_.mixin({
    groupByMulti: function(obj, val, arr) {
        var result = {};
        var iterator = typeof val == 'function' ? val : function(obj) {
                return obj[val];
            };
        _.each(arr, function(arrvalue, arrIndex) {
            _.each(obj, function(value, objIndex) {
                var key = iterator(value, objIndex);
                var arrresults = obj[objIndex][arrvalue];
                if (_.has(value, arrvalue))
                    (result[arrIndex] || (result[arrIndex] = [])).push(value);

My head hurts, but I think some more pushing needs to go here...

            });
        })
        return result;
    }
});

properties = _.groupByMulti(properties, function(item) {

    var testVal = item["size"];

    if (parseFloat(testVal)) {
        testVal = parseFloat(item["size"])
    }

    return testVal

}, multiGroup);

9条回答
Lonely孤独者°
2楼-- · 2019-01-08 14:50

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;
    });
});
查看更多
做自己的国王
3楼-- · 2019-01-08 14:54

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.

查看更多
家丑人穷心不美
4楼-- · 2019-01-08 14:57

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();
    }
  }
});
查看更多
登录 后发表回答