Creating Data Structures with Array.reduce()

I recently saw an older youtube video on using array.reduce to build data structures on the fly in ways that you may find surprising or unintuitive. Normally we always think of reduce when it comes to doing math on array elements or something similar, …


This content originally appeared on DEV Community and was authored by Garrick Crouch

I recently saw an older youtube video on using array.reduce to build data structures on the fly in ways that you may find surprising or unintuitive. Normally we always think of reduce when it comes to doing math on array elements or something similar, and while that is a great use case, lets explore some of the more unique ways leverage this array method.

Create An Object From An Array

To do this you could use any old loop, but lets say you need to build an object of objects, with the properties equal to one of the objects property values, eg.

// this is the data we have...
const data = [
  {
    id: 1,
    name: 'New Post',
    author: 'Jeff',
    date: '2021-05-01'
  },
  {
    id: 2,
    name: 'Newer Post',
    author: 'Sabrina',
    date: '2021-05-02'
  },
  {
    id: 3,
    name: 'Newest Post',
    author: 'Mike',
    date: '2021-05-02'
  },
  {
    id: 4,
    name: 'Fourth Post',
    author: 'Mike',
    date: '2021-03-02'
  },
  {
    id: 5,
    name: 'Fifth Post',
    author: 'Sabrina',
    date: '2021-08-09'
  }
];

// this is the structure we want...
const authors = {
  jeff: {
    posts: [
      {
        id: 1,
        title: 'Post Name',
        created_at: '2021-05-01'
      }
    ]
  },
  sabrina: {
    posts: [ ...posts ]
  },
  mike: {
    posts: [ ...posts ]
  },
}

Basically we want build an object containing author objects that each contain an array of any posts they've written. A map won't do because we don't really want to return an array of course (contrived on purpose for the example) and we would like to easily aggregate them into the appropriate arrays keyed by the name. Also the specification says we should rename the date to created_at and name to title.

So how could we reduce this array to the data structure specified in a functional way and it make sense to the reader of our code?

Remember that array.reduce will return any value you want it to...aha...so we want to return an object.

reduce((previousValue, currentValue) => { ... }, initialValue)

This above is the function we'll use. Notice the initialValue argument. That'll set the stage for our returned value.

Let's Reduce

(data || []).reduce((acc, curr) => ({}), {});

This is our basic setup. We'll pass acc or the accumulated value and the curr or current array element into the callback, returning an expression, which is an object literal. Our default value you may notice is an empty object.

const result = (data || []).reduce((acc, curr) => ({
  ...acc,
  [curr?.author?.toLowerCase()]: {
    ...acc[curr?.author?.toLowerCase()],
    posts: [
      ...(acc[curr?.author?.toLowerCase()]?.posts || []),
      {
        id: curr?.id,
        title: curr?.name,
        created_at: curr?.date
      }
    ]
  }
}), {});

This is our workhorse above. We'll step through each stage of working with the data. It's done in a functional way meaning we're copying data, never overwriting it.

First, we spread the value of acc into the object that we're returning
const result = data.reduce((acc, curr) => ({
  ...acc,
  // more stuffs
}), {});
Second, we'll use the computed value to set our property name of an author
const result = data.reduce((acc, curr) => ({
  ...acc,
  [curr?.author?.toLowerCase()]: {
    // more stuffs
  }
}), {});

This way it ensures we're preserving any objects that don't match the computed property name in the carry. We use the toLowerCase bc the spec says it wants lowercase author names as the object property.

Third, we'll set and spread on the posts property of a computed name author object
const result = data.reduce((acc, curr) => ({
  ...acc,
  [curr?.author?.toLowerCase()]: {
    ...acc[curr?.author?.toLowerCase()],
    posts: [
     // we'll use a short circuit since the posts property won't e 
     // exist on the first of any given author, just spread an 
     // empty array
      ...(acc[curr?.author?.toLowerCase()]?.posts || []),
     // add our object with the specified data mapping
      {
        id: curr?.id,
        title: curr?.name,
        created_at: curr?.date
      }
    ]
  }
}), {});
Success

If we serialize the result and pretty print it we'd get....

{
    "jeff": {
        "posts": [
            {
                "id": 1,
                "title": "New Post",
                "created_at": "2021-05-01"
            }
        ]
    },
    "sabrina": {
        "posts": [
            {
                "id": 2,
                "title": "Newer Post",
                "created_at": "2021-05-02"
            },
            {
                "id": 5,
                "title": "Fifth Post",
                "created_at": "2021-08-09"
            }
        ]
    },
    "mike": {
        "posts": [
            {
                "id": 3,
                "title": "Newest Post",
                "created_at": "2021-05-02"
            },
            {
                "id": 4,
                "title": "Fourth Post",
                "created_at": "2021-03-02"
            }
        ]
    }
}

Please leave me any thoughts on optimization or better ways to accomplish the given task. The primary focus of this is to get people thinking about array.reduce in interesting ways but I always enjoy learning new or better ways to do stuff.


This content originally appeared on DEV Community and was authored by Garrick Crouch


Print Share Comment Cite Upload Translate Updates
APA

Garrick Crouch | Sciencx (2021-10-20T00:05:06+00:00) Creating Data Structures with Array.reduce(). Retrieved from https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/

MLA
" » Creating Data Structures with Array.reduce()." Garrick Crouch | Sciencx - Wednesday October 20, 2021, https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/
HARVARD
Garrick Crouch | Sciencx Wednesday October 20, 2021 » Creating Data Structures with Array.reduce()., viewed ,<https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/>
VANCOUVER
Garrick Crouch | Sciencx - » Creating Data Structures with Array.reduce(). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/
CHICAGO
" » Creating Data Structures with Array.reduce()." Garrick Crouch | Sciencx - Accessed . https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/
IEEE
" » Creating Data Structures with Array.reduce()." Garrick Crouch | Sciencx [Online]. Available: https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/. [Accessed: ]
rf:citation
» Creating Data Structures with Array.reduce() | Garrick Crouch | Sciencx | https://www.scien.cx/2021/10/20/creating-data-structures-with-array-reduce/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.