Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 20, 2021 12:05 am GMT

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, 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.


Original Link: https://dev.to/localpathcomp/creating-data-structures-with-arrayreduce-13f

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To