Search code examples
javascriptarrayslodashramda.js

Javascript remove duplicate in a list of objects merging some properties


I have this list:

const debts = [
  {
    amount: 10,
    debtor: "Mark",
    creditor: "John"
  },
  {
    amount: 20,
    debtor: "Mark",
    creditor: "John"
  },
  {
    amount: 10,
    debtor: "Mark",
    creditor: "Tom"
   }
];

...and I want to merge the elements with the same debtor and creditor calculating the total amount, like this

const debts = [
  {
    amount: 30, // 10 + 20
    debtor: "Mark",
    creditor: "John"
  },
  {
    amount: 10,
    debtor: "Mark",
    creditor: "Tom"
   }
];

Could anyone help me? Thanks


Solution

  • If you're interested in a solution using Ramda, here's a suggestion:

    const {
      pipe,
      mergeWithKey,
      map,
      reduce,
      values,
      groupBy,
      props,
      join
    } = R;
    
    const debts = [{
        amount: 10,
        debtor: "Mark",
        creditor: "John"
      },
      {
        amount: 20,
        debtor: "Mark",
        creditor: "John"
      },
      {
        amount: 10,
        debtor: "Mark",
        creditor: "Tom"
      }
    ];
    
    const mergeAmount = mergeWithKey((key, left, right) => key === 'amount' ? left + right : left);
    const groupKey = pipe(props(['debtor', 'creditor']), join(' ~> '));
    
    const process =
      pipe(
        groupBy(groupKey),
        map(reduce(mergeAmount, {})),
        values);
    
    console.log(process(debts));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>


    The idea is to split the process in three steps:

    1. Group debtors and creditors together
    2. For each debtor/creditor group, merge the amount
    3. Extract each debtor/creditor group into an array

    Step 1: groupBy(groupKey)

    Step 1 gets the original debts array

    {
        "Mark ~> John": [
            {
                amount: 10,
                creditor: "John",
                debtor: "Mark"
            },
            {
                amount: 20,
                creditor: "John",
                debtor: "Mark"
            }
        ],
        "Mark ~> Tom": [
            {
                amount: 10,
                creditor: "Tom",
                debtor: "Mark"
            }
        ]
    }
    

    Step 2: map(reduce(mergeAmount, {}))

    Step 2 gets the output from step 1

    {
        "Mark ~> John": {
            amount: 30,
            creditor: "John",
            debtor: "Mark"
        },
        "Mark ~> Tom": {
            amount: 10,
            creditor: "Tom",
            debtor: "Mark"
        }
    }
    

    Step 3: values

    Step 3 gets the output from step 2

    [
        {
            amount: 30,
            creditor: "John",
            debtor: "Mark"
        },
        {
            amount: 10,
            creditor: "Tom",
            debtor: "Mark"
        }
    ]