2
\$\begingroup\$

I have an array with the days of the week:

const testArray = ['Monday', 'Friday', 'Saturday'];

I want to populate the values true or false of an object containing days of the week based on whether if the particular day is included in the given array. Right now I'm checking the array for each day like so:

{
  Monday: !!this.accountFeatures.BusinessDays?.includes('Monday'),
  Tuesday: !!this.accountFeatures.BusinessDays?.includes('Tuesday'),
  Wednesday: !!this.accountFeatures.BusinessDays?.includes('Wednesday'),
  Thursday: !!this.accountFeatures.BusinessDays?.includes('Thursday'),
  Friday: !!this.accountFeatures.BusinessDays?.includes('Friday'),
  Saturday: !!this.accountFeatures.BusinessDays?.includes('Saturday'),
  Sunday: !!this.accountFeatures.BusinessDays?.includes('Sunday'),
}

Is this not optimal since I'm checking the array 7 times, is there are better way to do this?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ There's not enough code here to review, but normally you'd use a loop over an all days array and use a condition to check if each day is included in the business days array. \$\endgroup\$
    – ggorlen
    Jun 22 at 13:59
  • 1
    \$\begingroup\$ testArray is defined but never used. \$\endgroup\$ Jun 22 at 15:01

3 Answers 3

5
\$\begingroup\$

Your code is very verbose and repetitive. As it is not a function it is not portable or easily reusable.

Example

  • Removes as much as the repetition as possible
  • Encapsulated in IIEF, the days of the week are passed as an array
  • Transportable. The function can be added as a property of an object without modification.
  • String of days this.accountFeatures.BusinessDays to test are passed to the function rather than accessing it in the function.
const WEEKDAYS = "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday".split(",");
const createBusinessDays = ((...weekdays) => days => weekdays.reduce((res, day) =>  
        (res[day] = days?.includes(day) ?? false, res), {})
)(...WEEKDAYS);

As part of an object

const WEEKDAYS = "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday".split(",");
const myObj = {
    accountFeatures: { BusinessDays: "Tuesday,Wednesday,Thursday,Sunday" },
    createBusinessDays: ((...weekdays) => days => weekdays.reduce((res, day) =>  
    (res[day] = days?.includes(day) ?? false, res), {})
    )(...WEEKDAYS),
};

// Call it using
const res = myObj.createBusinessDays(myObj.accountFeatures.BusinessDays);
console.log(res);

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Spread syntax is unnecessary here. ((...args)=>{})(...array) is the same as ((args)=>{})(array). \$\endgroup\$ Jun 22 at 22:59
  • \$\begingroup\$ @Unmitigated They are very different. The spread creates a copy of the array and ensures that the array copy is fully encapsulated and safe from mutation. \$\endgroup\$
    – Blindman67
    Jun 23 at 1:50
  • \$\begingroup\$ I see what you mean. That could have been accomplished by directly copying the array as well: (args=>{})([...arr]) \$\endgroup\$ Jun 23 at 2:26
0
\$\begingroup\$

When I know that I'll be searching in an array multiple times, I usually just put it in a Set.

The Set has method checks if a value is in a Set object, using an approach that is, on average, quicker than testing most of the elements that have previously been added to the Set object. In particular, it is, on average, faster than the Array.prototype.includes method when an Array object has a length equal to a Set object's size.

However, performance is irrelevant if we're only talking about maximum 7 items. 🤷‍♂️

You can also utilise Object#fromEntries which conveniently transforms an array like [['hello', 'world'],['foo', 'bar']] to { hello: 'world', foo: 'bar' }.

This is probably what I would do (simplified version of your situation).

const WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];

const BUSINESS_DAYS_SET = new Set(['Monday', 'Tuesday']);

const result = Object.fromEntries(WEEKDAYS.map((weekday) => [weekday, BUSINESS_DAYS_SET.has(weekday)]));

console.log(result);

\$\endgroup\$
0
\$\begingroup\$

Without knowing what the real word input array looks like, its hard to judge what could be the most efficient algorithm, but as its stands, you have 7*N potential iterations (where N in the length of the input array). It's not clear if the input array is a subset of days, or includes duplication.

If we assume that the input array is shorter than the number of days in the week, we can iterate the input array, reducing it against the 'default' of an object with all days represented, but set false.

const testArray = ['Monday', 'Friday', 'Saturday'];

const obj = testArray.reduce((acc, cur) => ({ ...acc, [cur]: true }), {
    Monday: false, Tuesday: false, Wednesday: false, Thursday: false, Friday: false, Saturday: false, Sunday: false,
})

console.log(obj)

If you think that the input array could be longer, it might pay to remove the duplication, putting the input array through a Set and back to an array before reducing.

const testArray = ['Monday', 'Friday', 'Saturday'];

const obj = [...new Set(testArray)].reduce((acc, cur) => ({ ...acc, [cur]: true }), {
        Monday: false, Tuesday: false, Wednesday: false, Thursday: false, Friday: false, Saturday: false, Sunday: false,
    })

console.log(obj)

I think it should go without saying that this could be encapsulated into a function to make the purpose clearer at the call site.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.