Home > Software engineering >  Using one array filter instead of multiple ones
Using one array filter instead of multiple ones

Time:11-11

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.

CodePudding user response:

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);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

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.

CodePudding user response:

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);
  • Related