1

Is there a way to merge all these filters into one? Or another way to make it more effective? Or just use for loop?

 driving += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'driving').length;
    breathWork += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'breath work').length;
    meditation += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'meditation').length;
    cooking += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'cooking').length;
    walking += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'walking').length;
    other += value.filter((obj) => obj.type === CalendarEventType.MIND && obj.data.practice === 'other').length;

They look to me very redudant.

user2994290
  • 329
  • 4
  • 13

3 Answers3

3

Currently you're looping 6 times over the same array. You can reduce the runtime with a simple for-loop or reduce:

const counts = value.reduce((acc, el) => {
  if (el.type !== CalendarEventType.MIND) return acc;
  acc[el.data.practice] = (acc[el.data.practice] ?? 0) + 1
  return acc;
}, {});

Example:

const CalendarEventType = {
  MIND: 1,
  OTHER: 2
};

const value = [
  {type: CalendarEventType.MIND, data: { practice: 'driving' } },
  {type: CalendarEventType.MIND, data: { practice: 'breath work' } },
  {type: CalendarEventType.OTHER, data: { practice: 'breath work' } },
  {type: CalendarEventType.MIND, data: { practice: 'other' } },
  {type: CalendarEventType.MIND, data: { practice: 'other' } },
  {type: CalendarEventType.OTHER, data: { practice: 'other' } },
];

const counts = value.reduce((acc, el) => {
  if (el.type !== CalendarEventType.MIND) return acc;
  acc[el.data.practice] = (acc[el.data.practice] ?? 0) + 1
  return acc;
}, {});

console.log(counts);
jabaa
  • 5,844
  • 3
  • 9
  • 30
1

You could take an array of values and use a single filter.

const
    practices = ['driving', 'breath work', 'meditation', 'cooking', 'walking', 'other'];
    filter = ({ type, data: { practice } }) => type === CalendarEventType.MIND && practices.includes(practice),
    result = value.filter(filter),
    count = values.reduce((sum, o) => sum + filter(o), 0);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

One possible way would be to group by data.practice. Since there's no native "group by" function, you could implement it yourself (as described here), or you could use a library like Lodash or Ramda.

Example, using Lodash's groupBy:

const filteredItems = value.filter((obj) => obj.type === CalendarEventType.MIND);
const groupedItems = groupBy(filteredItems, obj => obj.data.practice);

Then you can do whatever you want with groupedItems, e.g.:

driving += groupedItems['driving'] ? groupedItems['driving'].length : 0;

Note that if a given value for data.practice is not represented in filteredItems, then that key won't be present in groupedItems - hence the need to check for that key.

Donut
  • 110,061
  • 20
  • 134
  • 146