How to group or merge this array of objects in javascript?

前端 未结 8 818
悲&欢浪女
悲&欢浪女 2020-12-18 23:22

I have an array of objects like below for example.

{name: \"Mc Donald\", quantity: 4, maleCount: 1, femaleCount: 0}
{name: \"KFC\", quantity: 9, maleCou         


        
相关标签:
8条回答
  • 2020-12-18 23:39

    Lodash makes your life easy.

    _.map(_.groupBy(yourArrayHere, 'name'), (groupMembers, groupKey) => {
        let sumObject = {name: groupKey};
    
        _.forEach(['quantity', 'maleCount', 'femaleCount'], (property) => {
            sumObject[property] = 0;
            _.forEach(groupMembers, (member) => {
                sumObject[property] += member[property];
            });
        });
    
        return sumObject;
    });
    
    0 讨论(0)
  • 2020-12-18 23:43

    More functional/universal approach

    const normalizeValue = (value) => value === undefined ? 0 : value
    const sumUpProps = (props = []) => (a = {}, b = {}) => {
      const result = {}
      
      props.forEach((prop) => {
        result[prop] = normalizeValue(a[prop]) + normalizeValue(b[prop])
      })
    
      return result
    }
    
    const data = [
      {name: "Mc Donald", quantity: 4, maleCount: 1, femaleCount: 0},
      {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
      {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
      {name: "Mc Donald", quantity: 4, maleCount: 0, femaleCount: 1},
      {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1},
      {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
      {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1},
      {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1}
    ]
    
    const entries = {}
    const sumObjects = sumUpProps(['quantity', 'maleCount', 'femaleCount'])
    
    data.forEach((item) => {
      const entry = entries[item.name] || {}
    
      entries[item.name] = sumObjects(entry, item)
    })
    
    
    console.log(entries)

    0 讨论(0)
  • 2020-12-18 23:45

    You can use forEach() loop and add to new array. You can pass empty object as thisArg parameter that you can use as this in your callback function and in second forEach context of this will still be the same as in first callback function because of arrow function.

    var data = [{"name":"Mc Donald","quantity":4,"maleCount":1,"femaleCount":0},{"name":"KFC","quantity":9,"maleCount":1,"femaleCount":0},{"name":"KFC","quantity":9,"maleCount":1,"femaleCount":0},{"name":"Mc Donald","quantity":4,"maleCount":0,"femaleCount":1},{"name":"KFC","quantity":9,"maleCount":0,"femaleCount":1},{"name":"KFC","quantity":9,"maleCount":1,"femaleCount":0},{"name":"KFC","quantity":9,"maleCount":0,"femaleCount":1},{"name":"KFC","quantity":9,"maleCount":0,"femaleCount":1}]
    var result = [], keys = ['quantity', 'maleCount', 'femaleCount']
    
    data.forEach(function(e) {
      if(!this[e.name]) result.push(this[e.name] = e);
      else keys.forEach(k => this[e.name][k] += e[k])
    }, {})
    
    console.log(result)

    0 讨论(0)
  • 2020-12-18 23:46

    You can use array reduce:

    var arr = [
        {name: "Mc Donald", quantity: 4, maleCount: 1, femaleCount: 0},
        {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
        {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
        {name: "Mc Donald", quantity: 4, maleCount: 0, femaleCount: 1},
        {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1},
        {name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0},
        {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1},
        {name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1}
    ];
    
    var finalArr = arr.reduce((m, o) => {
        var found = m.find(p => p.name === o.name);
        if (found) {
            found.quantity += o.quantity;
            found.maleCount += o.maleCount;
            found.femaleCount += o.femaleCount;
        } else {
            m.push(o);
        }
        return m;
    }, []);
    
    console.log(finalArr);

    0 讨论(0)
  • 2020-12-18 23:52

    Here is a generic solution that uses clean and modern JavaScript:

    function groupRestaurants(restaurants) {
        const groups = new Map();
        restaurants.forEach(restaurant => {
            const group = findOrCreateGroup(groups, restaurant.name);
            addRestaurantToGroup(group, restaurant);
        });
        return [...groups.values()];
    }
    
    function findOrCreateGroup(groups, name) {
        let group = groups.get(name);
        if (!group) {
            group = { name };
            groups.set(name, group);
        }
        return group;
    }
    
    function addRestaurantToGroup(group, restaurant) {
        for (const [key, value] of Object.entries(restaurant)) {
            if (key !== 'name') {
                if (group.hasOwnProperty(key)) {
                    group[key] += value;
                } else {
                    group[key] = value;
                }
            }
        }
    }
    
    const restaurants = [
        { name: "Mc Donald", quantity: 4, maleCount: 1, femaleCount: 0 },
        { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 },
        { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 },
        { name: "Mc Donald", quantity: 4, maleCount: 0, femaleCount: 1 },
        { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 },
        { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 },
        { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 },
        { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }
    ];
    
    console.log(groupRestaurants(restaurants));

    0 讨论(0)
  • 2020-12-18 23:58

    You could group with a hash table and use an array for the keys with variable values.

    var array = [{ name: "Mc Donald", quantity: 4, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "Mc Donald", quantity: 4, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }],
        groups = Object.create(null),
        result = array.reduce(function (r, o) {
            var values = ['quantity', 'maleCount', 'femaleCount'];
            if (!groups[o.name]) {
                groups[o.name] = { name: o.name };
                r.push(groups[o.name]);
                values.forEach(function (k) { groups[o.name][k] = 0; });
            }
            values.forEach(function (k) { groups[o.name][k] += o[k]; });
            return r;
        }, []);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    With linq.js

    var array = [{ name: "Mc Donald", quantity: 4, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "Mc Donald", quantity: 4, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 1, femaleCount: 0 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }, { name: "KFC", quantity: 9, maleCount: 0, femaleCount: 1 }],
        result = Enumerable.From(array)
            .GroupBy(
                "$.name",
                null,
                "{ name: $.Key, quantity: $$.Sum('$.quantity'), maleCount: $$.Sum('$.maleCount'), femaleCount: $$.Sum('$.femaleCount') }"
            )
            .ToArray();
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>

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