Group by multiple values Underscore.JS but keep the keys and values

后端 未结 3 2018
日久生厌
日久生厌 2020-12-01 12:19

I\'m trying to group the following array with objects:

[ { user_id: 301, alert_id: 199, deal_id: 32243 },
  { user_id: 301, alert_id: 200, deal_id: 32243 },
         


        
相关标签:
3条回答
  • 2020-12-01 12:21

    Use groupBy with a function that creates a composite key using user_id and alert_id. Then map across the groupings to get what you want:

        var list = [ { user_id: 301, alert_id: 199, deal_id: 32243 },
          { user_id: 301, alert_id: 200, deal_id: 32243 },
          { user_id: 301, alert_id: 200, deal_id: 107293 },
          { user_id: 301, alert_id: 200, deal_id: 277470 } ];
    
        var groups = _.groupBy(list, function(value){
            return value.user_id + '#' + value.alert_id;
        });
    
        var data = _.map(groups, function(group){
            return {
                user_id: group[0].user_id,
                alert_id: group[0].alert_id,
                deals: _.pluck(group, 'deal_id')
            }
        });
    
    0 讨论(0)
  • 2020-12-01 12:24

    I would like to contribute a neat typescript ES6 group by.
    I am not really sure how to tighten up the return value typing. Some trickery is needed there, but this works rather well for me.

    /**
     * group the supplied list by a set of keys.
     * @param list the list of items to group.
     * @param children the key for the array of child items.
     * @param components the components to group by.
     */
    groupByMultipleFields<T, K extends keyof T>(
        list: T[],
        children: string,
        ...components: K[]): any[] {
    
        var grouping = [...list.reduce((r, o) => {
            const key = components.map(_ => `${o[_]}`).join(" :: ");
            var keyed = r.get(key) || components.reduce((x, y) => { x[y] = o[y]; return x; }, <T>{});
            keyed[children] = keyed[children] || [];
            keyed[children].push(o);
            return r.set(key, keyed);
        }, new Map).values()];
        return grouping;
    
    }
    

    You will need to turn on the typescript compiler option "downlevelIteration": true to allow the new Map to iterate and return values().

    0 讨论(0)
  • 2020-12-01 12:33

    For some specific task i had to to safe keys and values for it So i made this variant (with clean js):

    /**
     * Group your items in array by multiple keys!
     *
     * @param collection
     * @param retrieveFunctions
     * @param compareFunctions
     * @returns {Array}
     */
    function groupify(
        collection,
        retrieveFunctions = {attribute: value => value},
        compareFunctions = {attribute: (groupValue, value) => groupValue === value}
    ) {
        let groups = [];
        let keyValues = {};
    
        collection.forEach(item => {
            for (let attribute in retrieveFunctions) {
                keyValues[attribute] = retrieveFunctions.hasOwnProperty(attribute) ? retrieveFunctions[attribute](item[attribute]) : undefined;
            }
            let group = groups.find(group => {
                for (let key in retrieveFunctions) {
                    if (!group && !group.keys[key]) {
                        return false;
                    }
                    if (compareFunctions[key] instanceof Function) {
                        if (!compareFunctions[key](group.keys[key], keyValues[key])) {
                            return false;
                        }
                    } else if (group.keys[key] !== keyValues[key]) {
                        return false;
                    }
                }
    
                return true;
            });
    
            !group ? groups.push({keys: keyValues, items: [item]}) : group.items.push(item);
            keyValues = {};
        });
    
        return groups;
    }
    

    Here the link on gist: groupify.js

    0 讨论(0)
提交回复
热议问题