繁体   English   中英

使用 Lodash 按属性合并对象数组

[英]Merge Array of Objects by Property using Lodash

我有两个对象数组,它们表示具有标签和值的电子邮件地址:

var original = [
  {
    label: 'private',
    value: 'private@johndoe.com'
  },
  {
    label: 'work',
    value: 'work@johndoe.com'
  }
];

var update = [
  {
    label: 'private',
    value: 'me@johndoe.com'
  },
  {
    label: 'school',
    value: 'schhol@johndoe.com'
  }
];

现在我想通过label字段比较和合并两个数组,这样结果看起来像这样:

var result = [
  {
    label: 'private',
    value: 'me@johndoe.com'
  },
  {
    label: 'work',
    value: 'work@johndoe.com'
  },
  {
    label: 'school',
    value: 'schol@johndoe.com'
  }
]

我怎样才能做到这一点,例如使用lodash

_.unionBy() :
此方法类似于 _.union,不同之处在于它接受为每个数组的每个元素调用 iteratee 以生成计算唯一性的标准。 结果值是从出现该值的第一个数组中选择的

 var original = [ { label: 'private', value: 'private@johndoe.com' }, { label: 'work', value: 'work@johndoe.com' } ]; var update = [ { label: 'private', value: 'me@johndoe.com' }, { label: 'school', value: 'schol@johndoe.com' } ]; var result = _.unionBy(update, original, "label"); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

将列表转换为以label为键的对象,通过_.assign合并它们,然后将其转换回数组。 它甚至会保留大多数浏览器上项目的顺序。

 var original = [ { label: 'private', value: 'private@johndoe.com' }, { label: 'work', value: 'work@johndoe.com' } ]; var update = [ { label: 'private', value: 'me@johndoe.com' }, { label: 'school', value: 'schol@johndoe.com' } ]; console.log( _.map( _.assign( _.mapKeys(original, v => v.label), _.mapKeys(update, v => v.label) ) ) ); // or remove more duplicated code using spread console.log( _.map( _.assign( ...[original, update].map( coll => _.mapKeys(coll, v => v.label) ) ) ) );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>

也许有点晚了,但是我看到的所有解决方案都没有正确连接两个数组,它们使用其中一个数组进行循环,并且不会添加第二个数组中的任何多余元素(假设这是必需的) .

正确的方法是对两个数组进行排序并在两个数组中向前移动,合并匹配元素并添加两个数组中缺失的元素。 请在下面找到完整的解决方案。 这也需要 O(n+m),这是您可以获得的最佳结果(没有排序本身的计算成本)。 在我的代码中,我已经从数据库中得到了排序的数据。

 function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) { var array1Index = 0; var array2Index = 0; const merged = []; if (!alreadySorted) { array1.sort(compareFn); array2.sort(compareFn); } while (array1Index < array1.length && array2Index < array2.length) { var comparedValue = compareFn(array1[array1Index], array2[array2Index]); if (comparedValue === 0) { merged.push(mergeFn(array1[array1Index], array2[array2Index])); array1Index++; array2Index++; } else if (comparedValue < 0) { merged.push(mergeFn(array1[array1Index])); array1Index++; } else { merged.push(mergeFn(array2[array2Index])); array2Index++; } } while (array1Index < array1.length) { merged.push(mergeFn(array1[array1Index])); array1Index++; } while (array2Index < array2.length) { merged.push(mergeFn(array2[array2Index])); array2Index++; } return merged; } const array1 = [{ "id": 10, isArray1: true }, { "id": 11, isArray1: true }, { "id": 12, isArray1: true }, ]; const array2 = [{ "id": 8, isArray2: true }, { "id": 11, isArray2: true }, { "id": 15, isArray2: true }, ]; const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) { return a.id - b.id; }, function(a, b) { if (b) { return _.merge(a, b); } return _.merge(a, { isArray1: true, isArray2: true }); }); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

结果将是:

[ { id: 8, isArray2: true, isArray1: true },
  { id: 10, isArray1: true, isArray2: true },
  { id: 11, isArray1: true, isArray2: true },
  { id: 12, isArray1: true, isArray2: true },
  { id: 15, isArray2: true, isArray1: true } ]

我知道这不是所要求的,但以防万一有人在此页面上偶然发现这里是您在 ramda 中执行此操作的方法:

var original = [
  { label: 'private', value: 'private@johndoe.com' },
  { label: 'work', value: 'work@johndoe.com' }
];

var updated = [
  { label: 'private', value: 'me@johndoe.com' },
  { label: 'school', value: 'schol@johndoe.com' }
];

unionWith(eqBy(prop('label')), updated, original);

如果您正在使用 lodash 3.x 而_.unionBy()不存在,您可以组合_.union()_.uniq()以获得相同的结果。

var original = [
  { label: 'private', value: 'private@johndoe.com' },
  { label: 'work', value: 'work@johndoe.com' }
];

var update = [
  { label: 'private', value: 'me@johndoe.com' },
  { label: 'school', value: 'schol@johndoe.com' }
];

var result = _.uniq(_.union(update, original), "label"); 

console.log(result);

这是使用 Lodash 合并两个对象的另一种方法:

 let a = [{ content: 'aaa', name: 'bbb2' }, { content: 'aad', name: 'ccd' } ]; let b = [{ content: 'aaa', name: 'bbb' }, { content: 'aad1', name: 'ccd1' } ]; let c = [...a, ...b]; let d = _.uniq(c, function(data) { return data.content; }) console.log(d);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

也许有点晚了,但是我看到的所有解决方案都没有正确连接两个数组,它们使用其中一个数组进行循环,并且不会添加第二个数组中的任何多余元素(假设这是必需的) .

我有同样的观察,所以自己把一些东西放在一起。 这适用于我的用例,如果“标签”字段的值匹配,则合并每个对象:

const dataSetHashes = dataSets.map(dataSet => _.keyBy(dataSet, 'label'))
const resultHash = _.merge(
  {},
  ...dataSetLookups
)
const result = Object.values(resultLookup)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM