Home > Enterprise >  How to merge two object arrays of differing length, based on two object key
How to merge two object arrays of differing length, based on two object key

Time:05-25

I have 2 arrays, I'd like to combine them if they have the same two object keys.

If no match is found, still keep the object, but have the value as 0.

Example of Input

withdrawal: [
    {
        "id": "a1",
        "withdrawalAmount": 300,
        "user": "John"
    },
    {
        "id": "b2",
        "withdrawalAmount": 100,
        "user": "Mike"
    }
    {
        "id": "c3",
        "withdrawalAmount": 33,
        "user": "John"
    }
]


deposit: [
    {
        "id": "a1",
        "depositAmount": 123,
        "user": "John"
    },
    {
        "id": "c3",
        "depositAmount": 44,
        "user": "John"
    },
]

Expected Output

transactions: [
    {
        "id": "a1",
        "depositAmount": 123,
        "withdrawalAmount": 300,
        "user": "John"
    },
    {
        "id": "b2",
        "depositAmount": 0,
        "withdrawalAmount": 100,
        "user": "Mike"
    },
    {
        "id": "c3",
        "depositAmount": 44,
        "withdrawalAmount": 33
        "user": "John"
    },
]

This is the function I tried so far, but it doesn't work due the two input arrays being a different length.

function mergeArrayObjects(arr1, arr2) {
    return arr1.map((item, i) => {
      if (item.user === arr2[i].user) {
        //merging two objects
        return Object.assign({}, item, arr2[i])
      }
    })
  }

CodePudding user response:

You can achieve the result you want by processing the list of withdrawals and deposits using Array.reduce to an object with the id values as keys and deposit and withdrawal amounts as values; you can then take the values of that object to make the transactions array:

const withdrawal = [{
    "id": "a1",
    "withdrawalAmount": 300,
    "user": "John"
  },
  {
    "id": "b2",
    "withdrawalAmount": 100,
    "user": "Mike"
  }
]

const deposit = [{
    "id": "a1",
    "depositAmount": 123,
    "user": "John"
  },
  {
    "id": "c3",
    "depositAmount": 44,
    "user": "John"
  }
]

const transactions = Object.values(
  withdrawal
    .concat(deposit)
    .reduce((c, { id, depositAmount, withdrawalAmount, ...rest }) => {
      c[id] = c[id] || {}
      depositAmount = c[id]['depositAmount'] || depositAmount || 0;
      withdrawalAmount = c[id]['withdrawalAmount'] || withdrawalAmount || 0;
      c[id] = ({ id, depositAmount, withdrawalAmount, ...rest });
      return c;
    },
    {})
  )
  
console.log(transactions)
.as-console-wrapper { max-height: 100% !important; top: 0 }

CodePudding user response:

Presented below is one possible way to achieve the desired objective.

Code Snippet

// helper method to obtain all props 
// from array-elt matching "id"
const getInfo = (ar, argId) => (
  ar?.find(({ id }) => id === argId) ?? {}
);

// combine both arrays using "id"
const combineArrays = (ar1, ar2) => {
  // first get unique ids combining both arrays
  const uniqIds = [
    ...new Set(
      [...ar1, ...ar2]
      .map(({ id }) => id)
    )
  ];
  // now, for each unique id
  // simply get relevant info from both
  // arrays where element's match the "id"
  return uniqIds.map(id => ({
    id,
    ...getInfo(ar1, id),
    ...getInfo(ar2, id)
  }));
};

const withdrawal = [{
    "id": "a1",
    "withdrawalAmount": 300,
    "user": "John"
  },
  {
    "id": "b2",
    "withdrawalAmount": 100,
    "user": "Mike"
  }
];

const deposit = [{
  "id": "a1",
  "depositAmount": 123,
  "user": "John"
}];

// invoke the method and display the result
console.log(
  'combined both arrays as below:\n',
  combineArrays(withdrawal, deposit)
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

CodePudding user response:

In first iteration merge only common object then re-iterate both array and take only un-used item in final array.

class Transaction {
  constructor(transaction) {
    this.id = transaction.id;
    this.depositAmount = transaction.depositAmount | 0;
    this.withdrawAmount = transaction.withdrawalAmount | 0;
    this.user = transaction.user;
  }
}

let withdrawl = [
  {
    id: "a1",
    withdrawalAmount: 300,
    user: "John",
  },
  {
    id: "b2",
    withdrawalAmount: 100,
    user: "Mike",
  },
  {
    id: "c3",
    withdrawalAmount: 33,
    user: "John",
  },
];

let deposit = [
  {
    id: "a1",
    depositAmount: 123,
    user: "John",
  },
  {
    id: "c3",
    depositAmount: 44,
    user: "John",
  },
];


let transactions = [];

// merge the common key of two array into one array
withdrawl.forEach((item1) => {
  deposit.forEach((item2) => {
    if (item1.id === item2.id) {
      let combined = { ...item1, ...item2 };
      let transaction = new Transaction(combined);
      transactions.push(transaction);

      // mark the item as used
      // or set some flag to know
      // the item is used in the array
      item1.used = true;
      item2.used = true;
    }
  })
})

// now take all the unused item from the both array
// and push them to the transactions array
withdrawl.forEach((item1) => {
  if (!item1.used) {
    let transaction = new Transaction(item1);
    transactions.push(transaction);
  }
});

deposit.forEach((item2) => {
  if (!item2.used) {
    let transaction = new Transaction(item2);
    transactions.push(transaction);
  }
});

console.log(transactions);


CodePudding user response:

const withdrawal = [{
    "id": "a1",
    "withdrawalAmount": 300,
    "user": "John"
  },
  {
    "id": "b2",
    "withdrawalAmount": 100,
    "user": "Mike"
  }
]


const deposit = [{
  "id": "a1",
  "depositAmount": 123,
  "user": "John"
}, ]
const mergeArr = withdrawal.map(ele => {
  let other = deposit.find(({id}) => id === ele.id)
  return other ? {...ele, ...other} : {...ele, depositAmount : 0}
})
console.log(mergeArr)

CodePudding user response:

For large arrays go with Nick's approach (you will save a lot of cycles in the end)

For small amount of items in the array, a solution with find() can be good enough:

const withdrawal= [
    {
        "id": "a1",
        "withdrawalAmount": 300,
        "user": "John"
    },
    {
        "id": "b2",
        "withdrawalAmount": 100,
        "user": "Mike"
    },
    {
        "id": "c3",
        "withdrawalAmount": 33,
        "user": "John"
    }
]


const deposit= [
    {
        "id": "a1",
        "depositAmount": 123,
        "user": "John"
    },
    {
        "id": "c3",
        "depositAmount": 44,
        "user": "John"
    }
]

const transactions = withdrawal.map(item => ({"depositAmount": 0, ...item}));

deposit.forEach( item => {
  const found = transactions.find(x => x.id === item.id);
  if (found) {
      Object.assign(found,item);
  } else {
    transactions.push(Object.assign(item,{"withdrawalAmount": 0}));
  }
  });


console.log(transactions)

NOTE: this code assumes that you want the union of both arrays rather than the intersection

  • Related