Javascript 如何使用 Lodash 基于一个键合并两个集合?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35091975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:16:20  来源:igfitidea点击:

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

javascriptcollectionsmergelodash

提问by murvinlai

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

我有两个集合,对象有一个公共键“userId”。如下:

var _= require('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}
];

I want to merge them based on "userId" to produce:

我想根据“userId”合并它们以产生:

[ { userId: 'p1', item: 1, profile: 1 },
  { userId: 'p2', item: 2, profile:2 },
  { userId: 'p3', item: 4 } ]

I have these so far:

到目前为止,我有这些:

var u = _.uniq(_.union(a, b), false, _.property('userId'));

Which result in:

结果是:

[ { userId: 'p1', item: 1 },
  { userId: 'p2', item: 2 },
  { userId: 'p3', item: 4 },
  { userId: 'p1', profile: 1 },
  { userId: 'p2', profile: 2 } ]

How can I merge them now?

我现在如何合并它们?

I tried _.keyBy but it results in:

我试过 _.keyBy 但结果是:

{ p1: { userId: 'p1', profile: 1 },
  p2: { userId: 'p2', profile: 2 },
  p3: { userId: 'p3', item: 4 } }

which is wrong.

这是错误的。

What's the last step I should do?

我应该做的最后一步是什么?

回答by Tushar

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

您可以使用_.map(),_.assign()_.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>

回答by Jorjon

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+

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);

回答by Nina Scholz

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>');

回答by Nicolas Le Thierry d'Ennequin

Lodash has a mergemethod that works on objects (objects with the same key are merged). In this demo, the arrays aand bare first converted into objects (where userIdis the key), then merged, and the result converted back to an array (_.values) (getting rid of the keys). _.flattenis then necessary because _.valuesadds an extra level of array.

Lodash 有一个merge处理对象的方法(合并具有相同键的对象)。在这个演示中,数组ab首先被转换为对象(其中userId是键),然后合并,结果转换回数组(_.values)(去掉键)。_.flatten然后是必要的,因为_.values添加了额外的数组级别。

var u= _({}) // Start with an empty object
  .merge(
    _(a).groupBy("userId").value(),
    _(b).groupBy("userId").value()
  )
  .values()
  .flatten()
  .value();

回答by garrettmac

ES6+ version without lodash.

没有 lodash 的 ES6+ 版本。

 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>');   

回答by ofir fridman

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);