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)