Home > Enterprise >  Merge Duplicate values in Objects if more than one Objects fields are similar
Merge Duplicate values in Objects if more than one Objects fields are similar

Time:09-23

I am trying to merge duplicate values if more than one same fields are exists in another object.

In below example - I have multiple objects of same asset_id and event_code which is repeated so I need to keep one and merge their value. I tried to do that but not getting the proper solution and output for the same.

const transaction = [{
    value: 5,
    asset_id: 'ABC',
    event_code : 1
}, {
    value: 15,
    asset_id: 'HGF',
    event_code : 1
}, {
    value: 15,
    asset_id: 'XYZ',
    event_code : 2
}, {
    value: 20,
    asset_id: 'XYZ',
    event_code : 2
}, {
    value: 25,
    asset_id: 'DEF',
    event_code : 3
}, {
    value: 20,
    asset_id: 'HGF',
    event_code : 3
}, {
    value: 20,
    asset_id: 'HGF',
    event_code : 3
},
{
    value: 10,
    asset_id: 'ABC',
    event_code : 1
}];
 
let newArr = [];
transaction.forEach(function (obj, ind, arr) {
    if (ind === arr.length - 1 || obj.asset_id !== arr[ind   1].asset_id && obj.event_code!== arr[ind   1].event_code) {
        newArr.push(obj);
    } else {
        arr[ind   1].value = obj.value;
    }
});
 
console.log(newArr)

Expected Output Should be like this :

[{
   value: 15,
   asset_id: 'ABC',
   event_code: 1
}, {
   value: 15,
   asset_id: 'HGF',
   event_code: 1
}, {
   value: 35,
   asset_id: 'XYZ',
   event_code: 2
} {
   value: 25,
   asset_id: 'DEF',
   event_code: 3
}, {
   value: 40,
   asset_id: 'HGF',
   event_code: 3
}]

CodePudding user response:

here is the solution for you

    const arr = [{
    value: 5,
    asset_id: 'ABC',
    event_code : 1
}, {
    value: 15,
    asset_id: 'HGF',
    event_code : 1
}, {
    value: 15,
    asset_id: 'XYZ',
    event_code : 2
}, {
    value: 20,
    asset_id: 'XYZ',
    event_code : 2
}, {
    value: 25,
    asset_id: 'DEF',
    event_code : 3
}, {
    value: 20,
    asset_id: 'HGF',
    event_code : 3
}, {
    value: 20,
    asset_id: 'HGF',
    event_code : 3
},
{
    value: 10,
    asset_id: 'ABC',
    event_code : 1
}];
    const fun = (ar)=>{
     const output = ar.reduce((prev, curr) => {
      const tmp = prev.find(e => e.asset_id===curr.asset_id);
        if (tmp) {
          tmp.value = curr.value tmp.value;
        } else {
          prev.push({
            asset_id: curr.asset_id,
            event_code: curr.event_code,
            value : curr.value
          });
        }
        return prev;
      }, []);
      return output
    }
    console.log(fun(arr))

CodePudding user response:

Here's one approach. We:

  • Build a map-of-maps, keyed by asset_id

    • Whose values are maps, keyed by event_code
      • Whose values are lists of transactions sharing a common asset_id and event_code
    function buildMapOfMaps( transactionList ) {
      const mapOfMaps = new Map();
    
      for (const t of transactionList ) {
        let map = mapOfMaps.get( t.asset_id );
    
        if !map {
          map = new Map();
          mapOfMaps.set(t.asset_id,map);
        }
    
        let transactions = map.get( t.event_code );
        if (!transactions) {
          transactions = [];
          m.set( t.event_code, transactions );
        }
    
        transactions.push( t );
    
      }
    
      return mapOfMaps;
    }
    
  • Once we have that, we iterate over the map-of-maps, and roll up those transactions sharing a common asset_id and event_code into a single transaction

    function rollUpCommonTransactions( mapOfMaps ) {
      const rollup = [];
    
      for ( const map of mapOfMaps.values() ) {
        for ( const transactions of map.values() ) {
          const summary = transactions.reduce( (x,y) => {
            x.value  = y.value;
            return x;
          });
          rollup.push(summary);
        }
      }
    
      return rollup;
    }
    

Then it's just a matter of putting it all together:

function mergeTransactions( transactionList ) {
  const mapOfMaps = buildMapOfMaps(transactionList)
  const rollup = rollUpCommonTransactions(mapOfMaps);

  return rollup;
}

CodePudding user response:

You're on the right track but, rather than be concerned about the next element:

  • See if you can Array#find the current element (same asset_id and event_code) in newArr
  • If found, just increment the found element's value by obj.value
  • And if not found, add the current element to newArr

You could as well use Array#findIndex - (index) in which case old = newArr[index]

const transaction = [{ value: 5, asset_id: 'ABC', event_code : 1 }, { value: 15, asset_id: 'HGF', event_code : 1 }, { value: 15, asset_id: 'XYZ', event_code : 2 }, { value: 20, asset_id: 'XYZ', event_code : 2 }, { value: 25, asset_id: 'DEF', event_code : 3 }, { value: 20, asset_id: 'HGF', event_code : 3 }, { value: 20, asset_id: 'HGF', event_code : 3 }, { value: 10, asset_id: 'ABC', event_code : 1 }];
 
let newArr = [];
transaction.forEach(function (obj) {
    const old = newArr.find(
        ({asset_id,event_code}) => 
        asset_id === obj.asset_id && event_code === obj.event_code
    );
    if (old) {
        old.value  = obj.value;
    } else {
        newArr.push(obj);
    }
});
 
console.log(newArr)

  • Related