DEV Community

Manav Misra
Manav Misra

Posted on

Update a Data Set For Specified ๐Ÿ”‘s

TLDR: Gist

How can we write a 'utility' function that will take in a data set (think ๐Ÿค”Array of Objects), some Array of specified ๐Ÿ”‘s and some function and return a new 'data set' with the values for the specified ๐Ÿ”‘s updated as per the function that was passed in?

Yeah...that's hard to describe.

Here's a simple example where we want to double (doubler) only the specified values (keys) within our data set (data).

    const data = [
      {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      },
      {
        a: 7,
        b: 9,
        c: 0,
        d: 8
      },
      {
        a: 5,
        b: 0,
        c: 4,
        d: 3
      },
      {
        a: 9,
        b: 3,
        c: 7,
        d: 2
      }
    ];

    const keys = ["a", "d"];

    const doubler = num => num * 2;
Enter fullscreen mode Exit fullscreen mode

This post assumes that you are familiar with all concepts shown in the code ๐Ÿ‘†๐Ÿฝand that you also know about callback functions, map and reduce. You should also be able to follow ES2015 arrow function expressions and ES2015 Object spread operator.

This can be done more 'easily' with forEach, but let's do a more elegant 'functional approach' using reduce.

Since we want an Array that still contains all of the elements in data, map will be our choice. We want to 'map' ๐Ÿ—บ๏ธover every element inside of data... data.map(d => ๐Ÿค”.

Now, for each element, d, we want to then iterate over keys and at the end of that, we want just a single new Object with updated values. Well, any time, we are iterating over an Array and invoking a function on each element but we just want to get back 1 'total' or 'accumulated' or 'aggregated' piece of data, reduce is the way to go.

data.map(d =>
        // For every 'd', update all of the VALUES for some specified ARRAY of ๐Ÿ”‘s...'reduce' ๐Ÿ”‘s down to just 1 'updated object'.
        keys.reduce(
          (updatedObject, currentKey) =>
            /**
             * For each ๐Ÿ”‘...
             * 'Spread' the current data object, 'd'.
             * 'Spread' 'updatedObject' (it's empty on first iteration)
             * 'Spread' a newly created Object that contains only the current 'key'
             *  and INVOKE the given CALLBACK FUNCTION to create an updated VALUE.
             * 'merge' all of those OBJECTS ๐Ÿ‘†๐Ÿฝand keep going until all of ๐Ÿ”‘s are iterated.
             */
            ({ ...d, ...updatedObject, ...{ [currentKey]: doubler(d[currentKey]) } }),

          // Instantiate updatedObject as an empty Object
          {}
        )
      );
Enter fullscreen mode Exit fullscreen mode

Here it is wrapped up in a 'utility function' with JSDocs.

    /**
     * Update values of given ๐Ÿ”‘s in an object.
     * @param {Object} data
     * @param {Array} keys
     * @param {Function} cb - the 'update' to perform
     * @return {Object}
     */
    function updateSpecifiedKeys(data, keys, cb) {
      return data.map(d =>
        // For every 'd', update all of the VALUES for some specified ARRAY of ๐Ÿ”‘s...'reduce' ๐Ÿ”‘s down to just 1 'updated object'.
        keys.reduce(
          (updatedObject, currentKey) => ({
            ...d,
            ...updatedObject,
            ...{ [currentKey]: cb(d[currentKey]) }
          }),
          {}
        )
      );
    }
Enter fullscreen mode Exit fullscreen mode

Invoking this 'utility function' with the data that we started above: updateSpecifiedKeys(data, keys, doubler);


    const data = [
      {
        a: 1,
        b: 2,
        c: 3,
        d: 4
      },
      {
        a: 7,
        b: 9,
        c: 0,
        d: 8
      },
      {
        a: 5,
        b: 0,
        c: 4,
        d: 3
      },
      {
        a: 9,
        b: 3,
        c: 7,
        d: 2
      }
    ];

    const keys = ["a", "d"];

    const doubler = num => num * 2;

    function updateSpecifiedKeys(data, keys, cb) {
      return data.map(d =>
        // For every 'd', update all of the VALUES for some specified ARRAY of ๐Ÿ”‘s...'reduce' ๐Ÿ”‘s down to just 1 'updated object'.
        keys.reduce(
          (updatedObject, currentKey) => ({
            ...d,
            ...updatedObject,
            ...{ [currentKey]: cb(d[currentKey]) }
          }),
          {}
        )
      );
    }

    console.log(updateSpecifiedKeys(data, keys, doubler));
Enter fullscreen mode Exit fullscreen mode

    [
      { a: 2, b: 2, c: 3, d: 8 },
      { a: 14, b: 9, c: 0, d: 16 },
      { a: 10, b: 0, c: 4, d: 6 },
      { a: 18, b: 3, c: 7, d: 4 }
    ]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)