suuuriam
suuuriam

Reputation: 747

Improve nested forEach

I have this nested array:

const users = [
    ['User_1', [[1596232800000, 4]]],
    [
        'User_2',
        [
            [1591567200000, 3],
            [1591653600000, 16],
        ],
    ],
]

and would like this output:

const dataByDate = [
    {
        user: 'User_2',
        date: 1591567200000,
        count: 3,
    },
    {
        user: 'User_2',
        date: 1591653600000,
        count: 16,
    },
    {
        user: 'User_1',
        date: 1596232800000,
        count: 4,
    },
]

To achieve this I am doing this:


    const dataByDate: { date: string; count: number; user: string }[] = []

    users.forEach((user: string[]) => {
        if (user[1].length) {
            user[1].forEach((item: any) => {
                dataByDate.push({ date: item[0], user: user[0], count: item[1] })
            })
        }
    })

My solution works fine but I am wondering if there is a cleaner and more elegant solution than a nested forEach. Thanks!

Upvotes: 1

Views: 429

Answers (3)

Nick Parsons
Nick Parsons

Reputation: 50684

You can use .flatMap with an inner .map(). The inner .map() will take the second element of your inner array (ie: the [[date, count], ...] arrays), and map them to objects. Since .map() will result in an array of objects, you can use .flatMap() to merge the resulting objects into one final resulting array.

See example below:

const users = [
    ['User_1', [[1596232800000, 4]]],
    [
        'User_2',
        [
            [1591567200000, 3],
            [1591653600000, 16],
        ],
    ],
];

const result = users.flatMap(([user, arr]) => arr.map(([date, count]) => ({
  user, date, count
})));
console.log(result);

You can then apply the .sort() method for any additional reordering of the output array.

Upvotes: 4

Aadil Mehraj
Aadil Mehraj

Reputation: 2614

Using map and array destructuring, you can achieve this as:

const result = users
   .map(([ user, items ]) => {
      return items.flatMap(([date, count]) => ({ user, date, count }))
   })
   .flatMap(i => i)
   .sort((a,b) => a.date - b.date);

const users = [
        ['User_1', [[1596232800000, 4]]],
        [
            'User_2',
            [
                [1591567200000, 3],
                [1591653600000, 16],
            ],
        ],
    ]

const result = users.map(([ user, items ]) => {
  return items.flatMap(([date, count]) => ({ user, date, count }))
}).flatMap(i => i).sort((a,b) => a.date - b.date);

console.log({result})

Upvotes: 1

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20934

Use a combination of Array.prototype.flatMap() and Array.prototype.reduce(). The reduce loops over each data set for a user and creates and object per entry in that set. That object is then combined in the accumulating array.

Now flatMap returns a new array with objects for each user. The amount of objects are dependant on the amount of [date, count] entries and will be in a nested array. The flat part of flatMap takes care of this by putting every object in a single array.

const users = [
  [
    'User_1', [
      [1596232800000, 4]
    ]
  ],
  [
    'User_2', [
      [1591567200000, 3],
      [1591653600000, 16],
    ],
  ],
];

const formatUserData = users => users.flatMap(([ user, data ]) => 
  data.reduce((arr, [ date, count ]) => 
    [...arr, { user, date, count }], [])
  );
  
const result = formatUserData(users);

console.log(result);

Upvotes: 2

Related Questions