3
\$\begingroup\$

I have a function which from an array of days return the array of days with it's date like from array of

['Sun', 'Mon', 'Tue', 'Wed' ] my function returns the days from today if there are some past days i switch the date to next week so the array will become ['Wed 23', 'Sun 27', 'Mon 28', 'Tue 29' ]

And here is how my function looks like (i've added all comments that specify what i'm doing on each step:

 moment.locale('it'); // setting locale to italian as API response returns it formatted days
 const days = ['lun', 'mar', 'mer', 'gio', 'ven', 'sab', 'dom']; // mapping weekdays which will be used to get index of the day to use in isoWeekday
 const momentToday = moment().isoWeekday(); // setting today date
 const arrayGiorni = giorni.map((g) => {
 const dayIndex = days.indexOf(g.giorno.toLowerCase()); // getting index of day from the object array es if g.giorno is 'mar' index will be 2
 if (momentToday <= dayIndex) { // checking if today is <= to mapping object then adding it to array
 return {
 id: g.id,
 giorno: moment().isoWeekday(dayIndex),
 };
 } else { // else skipping to next week and adding the object to array
 return {
 id: g.id,
 giorno: moment()
 .add(1, 'weeks')
 .isoWeekday(dayIndex),
 };
 }
 });
// sorting the array to get an ordered array of dates
 arrayGiorni.sort((a, b) => moment(a.giorno).valueOf() - moment(b.giorno).valueOf());
// formatting the moment object to get string formatted date
 this.giorni = arrayGiorni.map(g => g.giorno.format('ddd DD MMM'));
 console.log(this.giorni);

As asked in comments here is the model of giorni:

export class NegozioGiorni {
 constructor(
 public id: number,
 public giorno: string,
 public orari: string[] = []
 ) {}
}

That in array of objects will be [ { id: 1, giorno: 'lun', orari: ['12:00', '13:00'] }, { id: 2, giorno: 'mer', orari: ['12:00', '13:00'] }, { id: 2, giorno: 'ven', orari: ['15:00', '17:00'] } ]

I was wondering if there is something that i can reduce in this come and if there is a way to make it more performable.

asked Sep 23, 2020 at 12:55
\$\endgroup\$
5
  • \$\begingroup\$ What kind of performance gains are you looking for, speed, memory, ...? \$\endgroup\$ Commented Sep 23, 2020 at 13:26
  • \$\begingroup\$ @pacmaninbw i'm looking for speed improvment as the array will always contains max 7 elements the memory is not so important in that case \$\endgroup\$ Commented Sep 23, 2020 at 14:01
  • 1
    \$\begingroup\$ @CertainPerformance added the example of giorni and it's constructor if needed \$\endgroup\$ Commented Sep 23, 2020 at 14:40
  • \$\begingroup\$ PS moment is no longer in active development. You should find something else. \$\endgroup\$ Commented Sep 23, 2020 at 15:31
  • 1
    \$\begingroup\$ The current question title of your question is too generic to be helpful. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$ Commented Sep 23, 2020 at 15:40

1 Answer 1

3
\$\begingroup\$

Speed You say you want the program to run more quickly, but it looks pretty good to me already. Are you really processing such a huge number of giorni objects that the function doesn't run fast enough? (It's possible, but it sounds unlikely.) But there are some improvements that could be made.

indexOf vs object You use indexOf to find the position of the day in the days array. This has O(n) complexity; the interpreter searches through the array indicies one-by-one until it finds a match. It would be less computationally expensive to use an object mapping day names to their indicies, then look up the name on the object, in a single operation.

Conditional values Inside the .map, the only part that changes between the if and else is the giorno property. To do this more efficiently and concisely, use the conditional operator instead:

return {
 id: g.id,
 giorno: momentToday <= dayIndex
 ? moment().isoWeekday(dayIndex)
 : moment().add(1, 'weeks').isoWeekday(dayIndex),
};

. Or, since it you don't actually care about the id properties, you can remove them entirely, and just use an array of times.

Moment Moment is a non-trivial library (and even it recommends to use modern APIs instead, like Date). If speed is an issue, you could use the native Date object instead.

const giorni = [{
 id: 1,
 giorno: 'lun', // Monday; turns into Mon 28 Sep
 orari: ['12:00', '13:00']
}, {
 id: 2,
 giorno: 'mer', // Wednesday: turns into Wed 23 Sep
 orari: ['12:00', '13:00']
}, {
 id: 2,
 giorno: 'ven', // Friday: turns into Fri 25 Sep
 orari: ['15:00', '17:00']
}];
const dayIndiciesByDayName = Object.fromEntries(
 ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab']
 .map((name, i) => [name, i])
);
const todayDayIndex = new Date().getDay(); // Zero-indexed and starts at Sunday
const todayDayOfMonth = new Date().getDate();
const inputDays = giorni.map(({ giorno }) => giorno);
const itemDates = giorni.map((g) => {
 const itemDayIndex = dayIndiciesByDayName[g.giorno.toLowerCase()];
 // Below will be 0 to 6:
 const itemDayDifferenceFromToday = (itemDayIndex - todayDayIndex + 7) % 7;
 const itemDateObj = new Date();
 itemDateObj.setDate(todayDayOfMonth + itemDayDifferenceFromToday);
 return itemDateObj;
});
const output = itemDates
 .sort((a, b) => a - b)
 .map((date) => {
 const match = date.toString().match(/(\w+ )(\w+) (\d+ )/);
 return match[1] + match[3] + match[2];
 });
console.log(output);

answered Sep 23, 2020 at 18:07
\$\endgroup\$
1
  • \$\begingroup\$ Awesome explanation, i've swapped to Date API as you suggested as i've just read that Moment has some memory leaks in modern frameworks and as i'm using Angular the Date was what i needed \$\endgroup\$ Commented Sep 24, 2020 at 6:42

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.