Search code examples
javascriptlodash

how to return object with some of its values modified lodash


const fruits = {
    apple: 2,
    orange: 3,
    grape: 4,
    banana: 5
}

I would like to modify some of the values of fruits where I also have access to its current value.

Something like this

const premiumFrutis = _.doSomething(fruits, apple + 2, banana + 3)

// premiumFrutis = {
//     apple: 4,
//     orange: 3,
//     grape: 4,
//     banana: 8
// }

Solution

  • This is the job of _.assignWith or _.assignInWith. The difference is that assignIn will go through the prototype chain but when dealing with plain objects, then both will work the same.

    In both cases, a customiser option can be provided which will be used when the values of the objects are combined. A simple implementation is

    const combineValues = (srcValue, objValue) => 
          srcValue + objValue;
    

    which will sum values for the same key:

    const fruits = {
        apple: 2,
        orange: 3,
        grape: 4,
        banana: 5
    }
    
    const combineValues = (srcValue, objValue) => 
      srcValue + objValue;
    
    const modification = {apple: 2, banana: 3};
    
    const premiumFrutis = _.assignWith(fruits, modification, combineValues);
    console.log(premiumFrutis);
    // {
    //     apple: 4,
    //     orange: 3,
    //     grape: 4,
    //     banana: 8
    // }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

    However, it is not even needed to implement this, since Lodash already provides _.add and it can be directly used:

    const fruits = {
        apple: 2,
        orange: 3,
        grape: 4,
        banana: 5
    }
    
    const modification = {apple: 2, banana: 3};
    
    const premiumFrutis = _.assignWith(fruits, modification, _.add);
    console.log(premiumFrutis);
    // {
    //     apple: 4,
    //     orange: 3,
    //     grape: 4,
    //     banana: 8
    // }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

    This will also do subtraction if you pass negative values:

    const fruits = {
        apple: 2,
        orange: 3,
        grape: 4,
        banana: 5
    }
    
    const modification = {apple: 2, banana: -1};
    
    const premiumFrutis = _.assignWith(fruits, modification, _.add);
    console.log(premiumFrutis);
    // {
    //     apple: 4,
    //     orange: 3,
    //     grape: 4,
    //     banana: 4
    // }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>


    The only potential problem is more modifications need to be passed than there are keys in the original objects:

    const fruits = {
        apple: 2,
        orange: 3,
        grape: 4,
        banana: 5
    }
    
    const modification = {apple: 2, banana: 3, lemon: 42};
    
    const premiumFrutis = _.assignWith(fruits, modification, _.add);
    console.log(premiumFrutis);
    // {
    //     apple: 4,
    //     orange: 3,
    //     grape: 4,
    //     banana: 8,
    //     lemon: 42
    // }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

    If no new items should be added, then _.pickBy can be used to remove any modifications that are not in the initial object:

    const fruits = {
        apple: 2,
        orange: 3,
        grape: 4,
        banana: 5
    }
    
    const modification = {apple: 2, banana: 3, lemon: 42};
    const onlyExisting = _.pickBy(modification, (value, key) => key in fruits);
    
    const premiumFrutis = _.assignWith(fruits, onlyExisting, _.add);
    console.log(premiumFrutis);
    // {
    //     apple: 4,
    //     orange: 3,
    //     grape: 4,
    //     banana: 8
    // }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>