Search code examples
javascriptlodash

how to concat two object arrays of different size by key using lodash


Stocks: [{
    PRN: 1,
    PID: 1,
    Qty: 3,
    SlNos: [1, 2, 3]
}, {
    PRN: 1,
    PID: 2,
    Qty: 4,
    SlNos: [10, 11, 12, 13]
}, {
    PRN: 2,
    PID: 1,
    Qty: 3,
    SlNos: [4, 5, 6]
}, {
    PRN: 2,
    PID: 2,
    Qty: 4,
    SlNos: [14, 15, 16, 17]
}]

I want this array as bellow with Lodash

Stocks: [{
    PID: 1,
    Qty: 6,
    SlNos: [1, 2, 3, 4, 5, 6]
}, {
    PID: 2,
    Qty: 4,
    SlNos: [10, 11, 12, 13, 14, 15, 16, 17]
}]

Solution

  • Here is a solution with _lodash:

    var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
    
    const result = _.reduce(stocks, (r, {PRN, ...c}) => {
       let _c = _.find(r, {'PID': c.PID})
       if(_c)
         _c = _.mergeWith(_c, c, (ov, sv, k) => _.includes(['Qty','SlNos'], k) ? _.isArray(sv) ? (ov || []).concat(sv) : _.isNumber(sv) ? sv + (ov || 0) : sv : ov)
       else
         r.push(c)
       return r
    }, [])
    
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

    We are using reduce with mergeWith (which is the main thing here really) plus a little bit of includes.

    Here is a solution without lodash that will do the trick:

    var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
    
    const result = stocks.reduce((r, c) => {
      _c = r.find(x => x.PID === c.PID)
      if (_c) {
        _c.PID = c.PID
        _c.Qty = _c.Qty + c.Qty
        _c.SlNos = _c.SlNos ? _c.SlNos.concat(c.SlNos) : c.SlNos
      } else {
        r.push(!delete(c.PRN) || c)
      }
      return r
    }, [])
    
    console.log(result)

    The idea is to use reduce and first find if we had already that object by PID if so sum the values if not insert to the final array. Since we are going through each record that logic does the trick in one loop.