Search code examples
javascriptarraysreactjsgroupingdate-range

Numbering array by month and reset to 1 on new month and year


I have data in an array which has a structure like this

[
    {createdAt: "2022-03-12T13:15:41.844+00:00", "name": 'adipiscing'},
    {createdAt: "2022-03-04T11:56:27.545+00:00", "name": 'consectetur'},
    {createdAt: "2021-01-15T09:12:25.418+00:00", "name": 'amet'},
    {createdAt: "2021-01-09T09:12:25.418+00:00", "name": 'sit'},
    {createdAt: "2021-01-02T08:52:55.418+00:00", "name": 'dolor'},
    {createdAt: "2021-12-15T09:12:25.418+00:00", "name": 'ipsum'},
    {createdAt: "2021-12-11T08:52:55.418+00:00", "name": 'lorem'},
]

The data above is sorted in desc by createdAt.

Currently for numbering I use the index data as usual, I want to change the numbering based on the createdAt column but at every change of month or entry in a new month or year, the number resets to 1 again

Can anyone help me, I'm very grateful.


Solution

  • The below may be one possible solution to achieve the desired objective:

    Code Snippet

    // helper method to get either YYYY-MM (if full=false) or YYYY-MM-DD (otherwise)
    const getDtYMD = (dt, full = false) => (
      full ? dt.createdAt.split('T')[0] : dt.slice(0, 7)
    );
    // transform the arr to add a group-id (idGroup)
    const sortAndGroup = arr => (
      Object.values( // get the values of the result object
        [...arr.map(x => ({...x}))].sort( // first sort the input-array reverse-chronological order (latest date at 0)
          (a, b) => (getDtYMD(a, true) > getDtYMD(b, true) ? 1 : -1)
        ).reduce( // use .reduce to iterate over the sorted array
          (acc, {createdAt : c, name}) => ({
            ...acc, // safe-keep existing accumulator object
            [getDtYMD(c)]: ([
              ...(acc[getDtYMD(c)] || []),
              { // append new object to value array for key YYYY-MM
                idGroup: (acc[getDtYMD(c)]?.length || 0) + 1,
                createdAt: c, // update 'idGroup' based on existing value-array's length
                name
              }
            ])
          }),
          {}
        )
      ).flat().sort(
        (a, b) => (
          getDtYMD(a, true) > getDtYMD(b, true)
          ? -1
          : getDtYMD(a, true) < getDtYMD(b, true)
            ? 1
            : a.idGroup > b.idGroup ? -1 : 1
        )
      )
    );
    
    
    const unsortedRawDataArray = [
        {'createdAt': "2022-03-12T13:15:41.844+00:00", "name": '1 adipiscing'},
        {'createdAt': "2022-03-04T11:56:27.545+00:00", "name": '1 consectetur'},
        {'createdAt': "2022-03-04T11:56:27.545+00:00", "name": '2 consectetur'},
        {'createdAt': "2022-03-04T11:56:27.545+00:00", "name": '3 consectetur'},
        {'createdAt': "2021-01-15T09:12:25.418+00:00", "name": '1 amet'},
        {'createdAt': "2021-01-09T09:12:25.418+00:00", "name": '1 sit'},
        {'createdAt': "2021-01-09T09:12:25.418+00:00", "name": '2 sit'},
        {'createdAt': "2021-01-09T09:12:25.418+00:00", "name": '3 sit'},
        {'createdAt': "2021-01-02T08:52:55.418+00:00", "name": '1 dolor'},
        {'createdAt': "2021-01-02T08:52:55.418+00:00", "name": '2 dolor'},
        {'createdAt': "2021-12-15T09:12:25.418+00:00", "name": '1 ipsum'},
        {'createdAt': "2021-12-11T08:52:55.418+00:00", "name": '1 lorem'},
    ];
    
    console.log('sorted-grouped: ', sortAndGroup(unsortedRawDataArray));
    console.log('original-array: ', unsortedRawDataArray);

    Explanation

    Description of the steps are added to the above code snippet as inline comments.

    EDIT

    when there is data that has the same date/day the order returns to 1 again,

    The data in the array has been updated to have multiple data with same date & the idGroup is shown to not reset.

    besides is there a way to reverse the number without changing the index, for example from 1-3 to 3-1.

    This has been done in the updated snippet. After the .flat() we add another .sort() which considers not just the date, but also the idGroup in order to make the numbers go from 3-1 (reverse).

    EDIT 2

    why after calling the sortAndGroup() function the data from unsortedRawDataArray also changes

    This has been fixed. The incoming arr (array) was directly mutated via .sort, and the latest version of the answer copies the arr array.