How to use Lodash to merge two collections based on a key?

前端 未结 6 1822
谎友^
谎友^ 2020-12-08 07:34

I have two collections, and the objects have a common key \"userId\". As below:

var _= require(\'lodash\');

var a = [
  { userId:\"p1\", item:1},
  { userId         


        
相关标签:
6条回答
  • 2020-12-08 07:38

    Highest voted answer doesn't do proper merge. If second array contains an unique property, it is not taken into account.

    This approach does a proper merge.

    Lodash

    var a = [
      { userId:"p1", item:1},
      { userId:"p2", item:2},
      { userId:"p3", item:4}
    ];
    
    var b = [
      { userId:"p1", profile:1},
      { userId:"p2", profile:2},
      { userId:"p4", profile:4}
    ];
    var merged = _.merge(_.keyBy(a, 'userId'), _.keyBy(b, 'userId'));
    var values = _.values(merged);
    console.log(values);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

    ES6+

    // from https://stackoverflow.com/a/34749873/80766
    const mergeDeep = (target, ...sources) => {
      if (!sources.length) return target;
      const source = sources.shift();
    
      if (target instanceof Object && source instanceof Object) {
        for (const key in source) {
          if (source[key] instanceof Object) {
            if (!target[key]) Object.assign(target, { [key]: {} });
            mergeDeep(target[key], source[key]);
          } else {
            Object.assign(target, { [key]: source[key] });
          }
        }
      }
    
      return mergeDeep(target, ...sources);
    }
    
    const a = [
      { userId:"p1", item:1},
      { userId:"p2", item:2},
      { userId:"p3", item:4}
    ];
    
    const b = [
      { userId:"p1", profile:1},
      { userId:"p2", profile:2},
      { userId:"p4", profile:4}
    ];
    
    
    const aKeyed = a.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
    const bKeyed = b.reduce((acc, cur) => ({ ...acc, [cur.userId]: cur }), {});
    const merged = mergeDeep(aKeyed, bKeyed);
    const values = Object.values(merged);
    console.log(values);

    0 讨论(0)
  • 2020-12-08 07:47

    Try this demo

    var a = [{
        userId: "p1",
        item: 1
    }, {
        userId: "p2",
        item: 2
    }, {
        userId: "p3",
        item: 4
    }];
    
    var b = [{
        userId: "p1",
        profile: 1
    }, {
        userId: "p2",
        profile: 2
    }];
    
    a.forEach(function (aitem) {
        b.forEach(function (bitem) {
            if(aitem.userId === bitem.userId) {
                _.assign(aitem, bitem);
            }
        });
    });
    
    console.log(a);
    
    0 讨论(0)
  • 2020-12-08 07:52

    Lodash has a merge method that works on objects (objects with the same key are merged). In this demo, the arrays a and b are first converted into objects (where userId is the key), then merged, and the result converted back to an array (_.values) (getting rid of the keys). _.flatten is then necessary because _.values adds an extra level of array.

    var u= _({}) // Start with an empty object
      .merge(
        _(a).groupBy("userId").value(),
        _(b).groupBy("userId").value()
      )
      .values()
      .flatten()
      .value();
    
    0 讨论(0)
  • 2020-12-08 07:56

    You can use _.map(), _.assign() and _.find().

    // Iterate over first array of objects
    _.map(a, function(obj) {
    
        // add the properties from second array matching the userID
        // to the object from first array and return the updated object
        return _.assign(obj, _.find(b, {userId: obj.userId}));
    });
    

    Fiddle Demo

    var a = [{
        userId: "p1",
        item: 1
    }, {
        userId: "p2",
        item: 2
    }, {
        userId: "p3",
        item: 4
    }];
    
    var b = [{
        userId: "p1",
        profile: 1
    }, {
        userId: "p2",
        profile: 2
    }];
    
    var arrResult = _.map(a, function(obj) {
        return _.assign(obj, _.find(b, {
            userId: obj.userId
        }));
    });
    
    console.log(arrResult);
    document.getElementById('result').innerHTML = JSON.stringify(arrResult, 0, 4);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.1.0/lodash.min.js"></script>
    <pre id="result"></pre>

    0 讨论(0)
  • 2020-12-08 07:56

    ES6+ version without lodash.

     const array1 = [{ userId: "p1", item: 1 },  { userId: "p2", item: 2 },{ userId: "p3", item: 4 }];
    const array2 = [{ userId: "p1", profile: 1 }, { userId: "p2", profile: 2 }];
    
    
    const result = array1.map(a => ({
      ...a,
      ...array2.find(b => b.userId === a.userId) // _.find(array2, 'skuId') <-- or with lodash 
    }));
    
     document.write('<pre>' + JSON.stringify(result, 0, 2) + '</pre>');   

    0 讨论(0)
  • 2020-12-08 07:57

    Just for completeness: A proposal without any library.

    function merge(a, b, key) {
    
        function x(a) {
            a.forEach(function (b) {
                if (!(b[key] in obj)) {
                    obj[b[key]] = obj[b[key]] || {};
                    array.push(obj[b[key]]);
                }
                Object.keys(b).forEach(function (k) {
                    obj[b[key]][k] = b[k];
                });
            });
        }
    
        var array = [],
            obj = {};
    
        x(a);
        x(b);
        return array;
    }
    
    var a = [
            { userId: "p1", item: 1 },
            { userId: "p2", item: 2 },
            { userId: "p3", item: 4 }
        ],
        b = [
            { userId: "p1", profile: 1 },
            { userId: "p2", profile: 2 }
        ],
        c = merge(a, b, 'userId');
    
    document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');

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