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.

3
  • Why do you have 6 different variables? Isn't that redundant in the first place? Commented Nov 10, 2021 at 18:09
  • I need to know the count of each "obj.data.practice" separatly. Commented Nov 10, 2021 at 18:12
  • Okay. It would have been better if you posted example of obj itself. The variables wouldn't be required at all Commented Nov 10, 2021 at 18:15

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

3 Comments

This is really good.
@Donut Thank you.
This is perfect! Thanks you
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.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.