【问题标题】:How to merge two arrays of objects by ID using lodash? [duplicate]如何使用lodash按ID合并两个对象数组? [复制]
【发布时间】:2016-12-01 11:09:25
【问题描述】:

我有两个数组和一个公共字段成员。如何轻松合并主题?

例如:

var arr1 = [{
  "member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),
  "bank" : ObjectId("575b052ca6f66a5732749ecc"),
  "country" : ObjectId("575b0523a6f66a5732749ecb")
},
{
  "member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),
  "bank" : ObjectId("575b052ca6f66a5732749ecc"),
  "country" : ObjectId("575b0523a6f66a5732749ecb")
}];

var arr2 = [{
    "member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),
    "name" : 'xxxxxx',
    "age" : 25
},
{
    "member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),
    "name" : 'yyyyyyyyyy',
    "age" : 26
}];

预期:

var merge = [{
  "member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),
  "bank" : ObjectId("575b052ca6f66a5732749ecc"),
  "country" : ObjectId("575b0523a6f66a5732749ecb"),
  "name" : 'xxxxxx',
  "age" : 25
},
{
  "member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),
  "bank" : ObjectId("575b052ca6f66a5732749ecc"),
  "country" : ObjectId("575b0523a6f66a5732749ecb"),
  "name" : 'yyyyyyyyyy',
  "age" : 26
}];

我试过了

var merge = _.unionBy(arr1, arr2, 'member');

但未按预期合并。显示 array1 值。谁能帮帮我?

【问题讨论】:

标签: javascript lodash


【解决方案1】:

如果两个数组的顺序都正确;其中每个项目对应于其关联的成员标识符,那么您可以简单地使用。

var merge = _.merge(arr1, arr2);

以下是短版:

var merge = _.chain(arr1).zip(arr2).map(function(item) {
    return _.merge.apply(null, item);
}).value();

或者,如果数组中的数据没有任何特定的顺序,您可以通过成员值查找关联的项目。

var merge = _.map(arr1, function(item) {
    return _.merge(item, _.find(arr2, { 'member' : item.member }));
});

您可以轻松地将其转换为 mixin。请看下面的例子:

_.mixin({
  'mergeByKey' : function(arr1, arr2, key) {
    var criteria = {};
    criteria[key] = null;
    return _.map(arr1, function(item) {
      criteria[key] = item[key];
      return _.merge(item, _.find(arr2, criteria));
    });
  }
});

var arr1 = [{
  "member": 'ObjectId("57989cbe54cf5d2ce83ff9d6")',
  "bank": 'ObjectId("575b052ca6f66a5732749ecc")',
  "country": 'ObjectId("575b0523a6f66a5732749ecb")'
}, {
  "member": 'ObjectId("57989cbe54cf5d2ce83ff9d8")',
  "bank": 'ObjectId("575b052ca6f66a5732749ecc")',
  "country": 'ObjectId("575b0523a6f66a5732749ecb")'
}];

var arr2 = [{
  "member": 'ObjectId("57989cbe54cf5d2ce83ff9d8")',
  "name": 'yyyyyyyyyy',
  "age": 26
}, {
  "member": 'ObjectId("57989cbe54cf5d2ce83ff9d6")',
  "name": 'xxxxxx',
  "age": 25
}];

var arr3 = _.mergeByKey(arr1, arr2, 'member');

document.body.innerHTML = JSON.stringify(arr3, null, 4);
body { font-family: monospace; white-space: pre; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.0/lodash.min.js"></script>

【讨论】:

  • _.map 中使用_.find 正在创建一个O(n^2) 解决方案。
  • 另请注意,此答案将省略 arr2 中不存在于 arr1 中的元素。更喜欢 Ori Drori 的回答。
  • 根本不起作用,我最终得到最后一个数组的值而不是两个合并数组
【解决方案2】:

使用_.keyBy()merge 为这两个数组创建字典,并使用_.values() 将结果转换为数组。这样,数组的顺序就无关紧要了。此外,它还可以处理不同长度的数组。

const ObjectId = (id) => id; // mock of ObjectId
const arr1 = [{"member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),"bank" : ObjectId("575b052ca6f66a5732749ecc"),"country" : ObjectId("575b0523a6f66a5732749ecb")},{"member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),"bank" : ObjectId("575b052ca6f66a5732749ecc"),"country" : ObjectId("575b0523a6f66a5732749ecb")}];
const arr2 = [{"member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),"name" : 'xxxxxx',"age" : 25},{"member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),"name" : 'yyyyyyyyyy',"age" : 26}];

const merged = _(arr1) // start sequence
  .keyBy('member') // create a dictionary of the 1st array
  .merge(_.keyBy(arr2, 'member')) // create a dictionary of the 2nd array, and merge it to the 1st
  .values() // turn the combined dictionary to array
  .value(); // get the value (array) out of the sequence

console.log(merged);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.0/lodash.min.js"></script>

使用 ES6 Map

将数组和reduce 合并的数组连接到一个映射。使用Object#assign 将具有相同member 的对象组合成一个新对象,并存储在地图中。使用Map#valuesspread 将地图转换为数组:

const ObjectId = (id) => id; // mock of ObjectId
const arr1 = [{"member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),"bank" : ObjectId("575b052ca6f66a5732749ecc"),"country" : ObjectId("575b0523a6f66a5732749ecb")},{"member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),"bank" : ObjectId("575b052ca6f66a5732749ecc"),"country" : ObjectId("575b0523a6f66a5732749ecb")}];
const arr2 = [{"member" : ObjectId("57989cbe54cf5d2ce83ff9d6"),"name" : 'xxxxxx',"age" : 25},{"member" : ObjectId("57989cbe54cf5d2ce83ff9d8"),"name" : 'yyyyyyyyyy',"age" : 26}];

const merged = [...arr1.concat(arr2).reduce((m, o) => 
  m.set(o.member, Object.assign(m.get(o.member) || {}, o))
, new Map()).values()];

console.log(merged);

【讨论】:

  • 是的,这个工作,而 lodash 惨败,只返回最后一个数组的内容
  • 如果数组总是相同大小,可以按id、zip、ma​​p排序
  • 我认为它可能会破坏顺序,因为 JS Object/Map 对象不保证任何。
  • 保证地图顺序,在ES6中保证object iteration order
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 2016-12-31
相关资源
最近更新 更多