Home > other >  How to group array of dates and sum value by day, 1hour, 6hours, 8hours, week, month, and year?
How to group array of dates and sum value by day, 1hour, 6hours, 8hours, week, month, and year?

Time:10-18

I have the array of dates and I want to group dates by year, month, week, day, 6h, 8h and 1h and sum value. for example, I have the following array:

const data = [
  { x: "2021-10-17T14:38:45.540Z", y: 2 },
  { x: "2021-09-16T14:36:46.540Z", y: 1 },
  { x: "2021-01-04T14:35:46.540Z", y: 2 },
  { x: "2021-01-01T14:30:46.540Z", y: 1 },
  { x: "2020-02-01T06:28:47.520Z", y: 12 },
  { x: "2020-02-01T07:28:47.520Z", y: 12 },
  // ...
  { x: "2019-04-13T10:19:20.034Z", y: 20 },
  // ...
  { x: "2018-01-01T09:09:19.134Z", y: 4 },
  { x: "2017-01-01T12:09:19.034Z", y: 11 },
  { x: "2016-01-02T12:10:20.034Z", y: 24 },
  // ...
]

This is what I tried using momentjs and lodash Group array of object by date

for year I got this result and the problem some years like 2018 and 2016 is not displayed:

 [
  {
    "color": "Blue",
    "value": 6,
    "label": "2021"
  },
  {
    "color": "Blue",
    "value": 24,
    "label": "2020"
  },
  {
    "color": "Blue",
    "value": 1212,
    "label": "2019"
  },
  {
    "color": "Blue",
    "value": 11,
    "label": "2017"
  }
]

Expected output for year:

[
      {
        "color": "Blue",
        "value": 6,
        "label": "2021"
      },
      {
        "color": "Blue",
        "value": 24,
        "label": "2020"
      },
      {
        "color": "Blue",
        "value": 1212,
        "label": "2019"
      },
      {
        "color": "Blue",
        "value": 10,
        "label": "2018"
      },
      {
        "color": "Blue",
        "value": 11,
        "label": "2017"
      },
      {
        "color": "Blue",
        "value": 48,
        "label": "2016"
      }
    ]

CodePudding user response:

This can be achieved with a standard 'group-by' using reduce, here accumulating into an object and returning an array using Object.values().

I've declared a simple get_date_parts helper to parse the ISO date strings which should be ample for grouping, but you can use a Date object for more complicated label formats if need be.

Here is the year grouping, the pattern can be adapted to all your other groupings, though you'll need to do a little arithmetic to determine hour ranges.

const data = [{ x: '2021-10-17T14:38:45.540Z', y: 2 }, { x: '2021-09-16T14:36:46.540Z', y: 1 }, { x: '2021-01-04T14:35:46.540Z', y: 2 }, { x: '2021-01-01T14:30:46.540Z', y: 1 }, { x: '2020-02-01T06:28:47.520Z', y: 12 }, { x: '2020-02-01T07:28:47.520Z', y: 12 }, { x: '2019-04-13T10:19:20.034Z', y: 20 }, { x: '2018-01-01T09:09:19.134Z', y: 4 }, { x: '2017-01-01T12:09:19.034Z', y: 11 }, { x: '2016-01-02T12:10:20.034Z', y: 24 },];

function get_date_parts(iso_string) {
  const [year, month, day, hr, min, sec] = iso_string.split(/\D/g);

  return { year, month, day, hr, min, sec };
}

function group_by_year(arr) {
  return Object.values(
    arr.reduce((a, { x: date_string, y: value }) => {
      const { year } = get_date_parts(date_string);
      (a[year] ??= { color: 'Blue?', value: 0, label: year }).value  = value;

      return a;
    }, {}),
  );
}

const grouped_by_year = group_by_year(data).sort((a, b) =>  b.label -  a.label);

console.log(grouped_by_year);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

or by month

const data = [{ x: '2021-10-17T14:38:45.540Z', y: 2 }, { x: '2021-09-16T14:36:46.540Z', y: 1 }, { x: '2021-01-04T14:35:46.540Z', y: 2 }, { x: '2021-01-01T14:30:46.540Z', y: 1 }, { x: '2020-02-01T06:28:47.520Z', y: 12 }, { x: '2020-02-01T07:28:47.520Z', y: 12 }, { x: '2019-04-13T10:19:20.034Z', y: 20 }, { x: '2018-01-01T09:09:19.134Z', y: 4 }, { x: '2017-01-01T12:09:19.034Z', y: 11 }, { x: '2016-01-02T12:10:20.034Z', y: 24 },];

function get_date_parts(iso_string) {
  const [year, month, day, hr, min, sec] = iso_string.split(/\D/g);

  return { year, month, day, hr, min, sec };
}

function group_by_month(arr) {
  return Object.values(
    arr.reduce((a, { x: date_string, y: value }) => {
      const { year, month } = get_date_parts(date_string);
      const key = `${year}/${month}`;
      (a[key] ??= { color: 'Blue?', value: 0, label: key }).value  = value;

      return a;
    }, {}),
  );
}

const grouped_by_month = group_by_month(data).sort((a, b) => b.label.localeCompare(a.label));

console.log(grouped_by_month);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related