簡體   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