JS filter array or arrays with unknown length?

Viewed 88

I have some data I'm trying to transform by filtering by date, however the data can vary in length i.e like this;

longData = [
     // These objects could be unlimited but the name key will always be unique
    {name: Opt 1,
     Data:
         // The first value will always be a date string and the second is the amount, the length of this array is always unknown
         ['2021-01-02', 30],
         ['2021-01-03, 20],
         ['2021-02-05', 15]
     },
     {name: Opt 2,
     Data:
         ['2021-01-02', 30],
         ['2021-02-08, 20],
         ['2021-04-02, 15]
     },
     {name: Opt 3,
     Data:
         ['2021-03-02', 30],
         ['2021-03-04, 20]
     }

What I want to do is essentially create a new object that has the same shape and the original but only includes the data between my dates.

I.e if I have a start date of '2021-01-01' and end of date '2021-01-07'

I should get an object like the following..

shortData = [
    {name: Opt 1,
     Data:
         ['2021-01-02', 30],
         ['2021-01-03, 20]
     },
     {name: Opt 2,
     Data:
         ['2021-01-02', 30]
     },
     {name: Opt 3,
     Data:
         []
     }

I'm trying to break it down by week, these numbers are rendered in a chart and when dealing with large data sets it can break the chart essentially, so I'm trying to page it by week.

Any thoughts on how to accomplish it would be rather helpful.

2 Answers

You can create a function filterByDate which takes your start date and end date strings and converts them into date objects. Then, for each object in longData, you can map it to a transformed object containing a new Data property, which is the filtered version of your Data array.

const longData = [{ name: "Opt 1", Data: [ ['2021-01-02', 30], ['2021-01-03', 20], ['2021-02-05', 15] ] }, { name: "Opt 2", Data: [ ['2021-01-02', 30], ['2021-02-0', 8, 20], ['2021-04-02', 15] ] }, { name: "Opt 3", Data: [ ['2021-03-02', 30], ['2021-03-04', 20] ] } ];

const isBetween = (dx, d1, d2) => d1 < dx && dx < d2;
const filterByDate = (data, start, end) => {
  const startDate = new Date(start);
  const endDate = new Date(end);
  return data.map(obj => ({...obj, Data: obj.Data.filter(
    ([date]) => isBetween(new Date(date), startDate, endDate)
  )}));
}

const res = filterByDate(longData, '2021-01-01', '2021-01-07');
console.log(res);

Given the following array of objects:

const data = [
  {
    name: "Opt 1",
    Data: [
      ["2021-01-02", 30],
      ["2021-01-03", 20],
      ["2021-02-05", 15],
    ],
  },
  {
    name: "Opt 2",
    Data: [
      ["2021-01-02", 30],
      ["2021-02-08", 20],
      ["2021-04-02", 15],
    ],
  },
  {
    name: "Opt 3",
    Data: [
      ["2021-03-02", 30],
      ["2021-03-04", 20],
    ],
  },
];

And you simply want to return the same array so that it filters Data property (which is an array of unknown length) by a given date (i.e. "2021-01-02"), I would use Array.prototype.reduce, spread syntax, and Array.prototype.filter to create the new data but with the Data property filtered so that it matches the given date (or in your case, falls within a start & end date):

let newData = data.reduce(
  (acc, curr) => [
    ...acc,
    { ...curr, Data: curr.Data.filter((d) => d[0] === "2021-01-02") },
  ],
  []
);

// [
//   { name: "Opt 1", Data: [["2021-01-02", 30]] },
//   { name: "Opt 2", Data: [["2021-01-02", 30]] },
//   { name: "Opt 3", Data: [] },
// ];
Related