如何使用lodash合并两个数组并对重复对象的值求和

10

有两个数组:

[
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 1},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 5},
  {"id": "342343343t4t34rwefewfd53", "quantity": 3}
]

[
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 2},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 1}
]
如何将它们合并为一个总和数量?
[
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 3},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 6},
  {"id": "342343343t4t34rwefewfd53", "quantity": 3}
]

它们中的一个有时可能为空


你应该添加你尝试过的代码。 - Andy
请参考以下链接[合并数组](https://www.samanthaming.com/tidbits/49-2-ways-to-merge-arrays) - Jeyam Prakash
7个回答

13

你可以使用纯JavaScript实现。

使用Array.reduce()通过id创建一个中间字典并累加数量,然后使用Object.values()将其转换为数组:

const arr1 = [
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 1},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 5},
  {"id": "342343343t4t34rwefewfd53", "quantity": 3}
];
const arr2 = [
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 2},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 1}
];

const result = Object.values([...arr1, ...arr2].reduce((acc, { id, quantity }) => {
  acc[id] = { id, quantity: (acc[id] ? acc[id].quantity : 0) + quantity  };
  return acc;
}, {}));

console.log(result);


4
你可以使用lodash,但现代的纯JavaScript同样可行和高效。我想其他答案将使用像reduce这样的函数方法,所以这里提供一个使用简单的for/of循环和find而不是字典查找的版本,虽然可能会更长一些,但更容易理解。

const arr1 = [{"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 1}, {"id": "344430b94t4t34rwefewfdff", "quantity": 5}, {"id": "342343343t4t34rwefewfd53", "quantity": 3}];
const arr2 = [{"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 2}, {"id": "344430b94t4t34rwefewfdff", "quantity": 1}];

function merge(arr1, arr2) {

  // Merge the arrays, and set up an output array.
  const merged = [...arr1, ...arr2];
  const out = [];

  // Loop over the merged array
  for (let obj of merged) {

    // Destructure the object in the current iteration to get
    // its id and quantity values
    const { id, quantity } = obj;

    // Find the object in out that has the same id
    const found = out.find(obj => obj.id === id);

    // If an object *is* found add this object's quantity to it...
    if (found) {
      found.quantity += quantity;

    // ...otherwise push a copy of the object to out
    } else {
      out.push({ ...obj });
    }
  }
  
  return out;

}

console.log(merge(arr1, arr2));


2
所有这些答案都需要您了解对象结构以选择和求和。
实际上,lodash允许您在不知道结构的情况下使用_.mergeWidth的customizer参数来完成此操作。
let result = _.mergeWith(arr1, arr2, (objValue, srcValue, key, object, source, stack) =>{
    
    //Add any conditions you need here. Ive added a few relevant examples. 
    //if(key.startsWith("num")) //Check for property name prefixes like num...
    //if(propertyNamesToSum.Includes(key)) //check if your property is in your predefined list of property names
    //This one below sums any properties that are numbers
    if(_.isNumber(srcValue) && _.isNumber(objValue)){
        return srcValue + objValue;
    } 
    return undefined; //lodash will merge as usual if you return undefined. 

});

Lodash文档 - https://lodash.com/docs/4.17.15#mergeWith


2
你可以使用 reduce 来实现这个功能:
```最初的回答```

let a1 = [
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 2},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 1}
];

let a2 = [
  {"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 1},
  {"id": "344430b94t4t34rwefewfdff", "quantity": 5},
  {"id": "342343343t4t34rwefewfd53", "quantity": 3}
];

let result = Object.values(a1.concat(a2).reduce((acc, v) => {
   if (!acc[v.id]) {
       acc[v.id] = {id: v.id, quantity: 0};
   }
   acc[v.id].quantity += v.quantity;
   return acc;
}, {}));

console.log("Results: ", result);


1
你可以使用 .reduce 和 .find 方法来实现这个功能。

const arr1 = [{"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 1}, {"id": "344430b94t4t34rwefewfdff", "quantity": 5}, {"id": "342343343t4t34rwefewfd53", "quantity": 3}];
const arr2 = [{"id": "5c5030b9a1ccb11fe8c321f4", "quantity": 2}, {"id": "344430b94t4t34rwefewfdff", "quantity": 1}];

const result =  [...arr1, ...arr2].reduce((accumulator, currentValue) => {
  const element = accumulator.find(item => item.id === currentValue.id)
  element ? element.quantity += currentValue.quantity : accumulator.push(currentValue)
  return accumulator
},[])

console.log(result)


0
该函数使用lodash的reduce和mapValues方法将对象数组中指定键的值相加,最终返回一个包含所有指定键的总和的对象。它允许每个对象中存在缺失的键。

const mergeAndSumObjVals = (objs, keys) => _.reduce(
  objs,
  (o, s) => _.mapValues(o, (v, k) => (v || 0) + (s[k] || 0)),
  _.chain(keys).invert().mapValues(() => 0).value(),
)


const objs = [{
  negative: 54,
  positive: 2
}, {
  inconclusive: 8,
  positive: 1
}, {
  negative: 26,
  inconclusive: 5,
  positive: 4
}]

const result = mergeAndSumObjVals(objs, ['negative', 'inconclusive', 'positive'])

console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>


0

带有额外对象键的版本。 函数体不会干扰哪个对象具有属性。 因此按“qty”求和并按“prop”检查

var first = [ 
  {quantity:100, id:1, variantId: 1}, 
  {quantity:300, id:2, variantId: 2, propA: 'aaa'},

];

var second = [
  {quantity:100, id:1, variantId: 1},
  {quantity:200, id:2, variantId: 2, propB: true}, 
  {quantity:300, id:3, variantId: 3, propC: 'ccc'}, 
]

function mergeArrays(arrayOfArrays, propToCheck, propToSum) {
    let sum = [];
    [].concat(...arrayOfArrays).map(function(o) {
        
        let existing = sum.filter(function(i) { return i[propToCheck] === o[propToCheck] })[0];
    
        if (!existing) {

            sum.push(o);
        } else {

            existing[propToSum] += o[propToSum];
            
            let copyProps = Object.keys(o).filter(obj => {
                  return existing[obj] !== o[obj]
            }).map(val => (val !== propToSum) ? existing[val] = o[val] : null)
        }
             
    });

    return sum;
}

console.log(mergeArrays([first, second], 'variantId', 'quantity'))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接