How to merge 2 arrays based on a key name and sort

2019-07-13 00:13发布

问题:

assume I have two list

const listA = [{"apple":100}, {"banana": 50}, {"pearl": 10}, {"cherry": 5}, {"kiwi": 3}]
const listB = [{"peach": 30}, {"apple": 15}, {"kiwi": 10}, {"mango": 5}]

The question is how do I merge two list into one stack up the same item with number increment and sort by the qty? I mean the final result should be ->

const listMerged = [{"apple":115}, {"banana": 50} , {"peach": 30}, {"kiwi": 13}, {"pearl": 10}, {"cherry": 5}, {"mango": 5}]

I know it is gonna be something like :

sortListDesc(list) {

    return obj.sort(function (l1,l2) {
      return l2< l1 ? -1
           : l2 >l1 ? 1
           : 0
    })
  }

but do not know exactly how to stack up the number, than sort by qty number.

回答1:

You can use reduce, and sort and Object.values like this:

const listA = [{"apple":100}, {"banana": 50}, {"pearl": 10}, {"cherry": 5}, {"kiwi": 3}]
, listB = [{"peach": 30}, {"apple": 15}, {"kiwi": 10}, {"mango": 5}]

let merged = Object.values(listA.concat(listB).reduce((acc, a) => {
  const [k, v] = Object.entries(a)[0];
  (acc[k] = acc[k] || {[k]: 0})[k] += v;
  return acc;
}, {}));

merged.sort((a, b) => Object.values(b)[0] - Object.values(a)[0]);
console.log(merged);

Or,

Using reduce, create an object with all the fruits as keys and individual sum as values. Then use Object.entries, sort and map like this:

const listA = [{"apple":100}, {"banana": 50}, {"pearl": 10}, {"cherry": 5}, {"kiwi": 3}]
, listB = [{"peach": 30}, {"apple": 15}, {"kiwi": 10}, {"mango": 5}]

let merged2 = listA.concat(listB).reduce((acc, a) => {
  const [k, v] = Object.entries(a)[0];
  acc[k] = (acc[k] || 0) + v;
  return acc;
}, {});

const final = Object.entries(merged2)
  .sort(([, v1], [, v2]) => v2 - v1)
  .map(([k, v]) => ({[k]: v}))

console.log(final);



回答2:

You can iterate the second list using forEach and check if the same element is present in the first list using findIndex. If the element is not present(-1) then push the element in first list. If it is present then using the index get that object and then update its value inside a for..in

const listA = [{
  "apple": 100
}, {
  "banana": 50
}, {
  "pearl": 10
}, {
  "cherry": 5
}, {
  "kiwi": 3
}]
const listB = [{
  "peach": 30
}, {
  "apple": 15
}, {
  "kiwi": 10
}, {
  "mango": 5
}]
let newArr = listB.forEach((item) => {
  let ifElemPresentInListA = listA.findIndex((elem) => {
    return Object.keys(elem)[0] === Object.keys(item)[0]

  })

  if (ifElemPresentInListA === -1) {
    listA.push(item)
  } else {
    for (let keys in listA[ifElemPresentInListA]) {
      listA[ifElemPresentInListA][keys] += Object.values(item)[0]
    }
  }

})

console.log(listA)



回答3:

I think I have a slightly cleaner code than the one from brk

const listA = [{"apple":100}, {"banana": 50}, {"pearl": 10}, {"cherry": 5}, {"kiwi": 3}]
const listB = [{"peach": 30}, {"apple": 15}, {"kiwi": 10}, {"mango": 5}]

const both = Object.assign({}, ... listA, ... listB); // concatenate both lists and convert them to an object
const lA = Object.assign({}, ...listA); // convert listA to an object
const lB = Object.assign({}, ...listB);

var result = Object.keys(both).map( (a) => { // mapping sums the values and yields an array
  var sum = {};
  sum [a] =(lA[a] ? lA[a] : 0) + (lB[a] ? lB[a] : 0);
  return sum;
});
// sorting in desc order (hence b - a ) based on values (hence b[Object.keys(b)]) rather than keys
result.sort((a,b) => b[Object.keys(b)] - a[Object.keys(a)] ); 

The complexity is due to the fact that you store the values as an array. I believe this is not the best way to have it for the reason that array can have multiple elements with the same keys. E.g. you can end up with something like this: const listA = [{"apple":100},...,{"apple":10}] which is valid but can make a problem. I suggest you to consider using it just as an Object e.g.: const listA = {{'apple': 100}, {'banana':50}} this will simplify the code significantly and make sure you don't have duplicates

Hope that helps!