I have a working solution of this problem but I'm trying to make a cleaner and neat version of it as much as possible. I came up with another solution that uses a function within a map function. Unfortunately, this version has a few issues and I want to just know why the second solution is not working. I'm guessing it's a variable scope issue here. I'm looking forward to know your opinion about it.
I have a simple function that prints calendar days in an array!
So a question is why the first version of my code get the expected results while the second version prints unexpected results.
I tried to change let
to var
and I also made the counter
and startedIndexing
outside the function scope.
Solution 1 (works):
const currentFullMonth = {
days_length: 31,
first_day: "Thu",
first_day_index: 4,
last_day: "Sat",
last_day_index: 6,
month: "Aug",
year: 2019
}
const testMonth = [
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]
];
function printMonthCalender(month) {
let counter = 0;
let startedIdxing = false;
return month.map(week => {
return week.map((day, index) => {
if (index === currentFullMonth.first_day_index && !startedIdxing) {
counter++;
startedIdxing = true;
return counter;
} else if (startedIdxing) {
if (currentFullMonth.days_length === counter) {
counter = 0;
}
counter++;
return counter;
} else {
return 0;
}
});
});
} // end of Solution #1 <-- this works :)
Solution 2 (doesn't work):
// start of Solution #2 <-- does not work :(
// im using two functions to make it look more cleaner
//
function printMonthCalender2(month) {
let counter = 0;
let startedIdxing = false;
return month.map(week => {
return week.map((day, index) =>
indexingMonth(counter, startedIdxing, index)
);
});
}
function indexingMonth(counter, startedIdxing, index) {
if (index === currentFullMonth.first_day_index && !startedIdxing) {
counter++;
startedIdxing = true;
return counter;
} else if (startedIdxing) {
if (currentFullMonth.days_length === counter) {
counter = 0;
}
counter++;
return counter;
} else {
return 0;
}
}// end of Solution #2
console.log(printMonthCalender(testMonth));
console.log(printMonthCalender2(testMonth));
expected result as follows (first version):
[0, 0, 0, 0, 1, 2, 3]
[4, 5, 6, 7, 8, 9, 10]
[11, 12, 13, 14, 15, 16, 17]
[18, 19, 20, 21, 22, 23, 24]
[25, 26, 27, 28, 29, 30, 31]
[1, 2, 3, 4, 5, 6, 7]
unexpected result as follows (second version):
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0]
The problem is that when you reassign startedIdxing
inside of indexingMonth
, it's a local variable, so it doesn't get changed inside of the calling function (printMonthCalender2
).
An issue is that .map
should not have mutation or reassignment as a side-effect. While you could tweak things so that indexingMonth
returned something that you checked and then reassigned startedIdxing
to, I'd prefer a different approach: create a flat array, eg
[0, 0, 0, 0, 1, 2, ..., 30, 31, 1, 2, 3]
and then chunk it into pieces of 7 afterwards:
const currentFullMonth = {
days_length: 31,
first_day: "Thu",
first_day_index: 4,
last_day: "Sat",
last_day_index: 6,
month: "Aug",
year: 2019
}
const makeZeroArr = length => new Array(length).fill(0);
const printMonthCalendar = (testMonth) => {
// Create array: [1, 2, 3, ..., 30, 31]
const oneMonth = Array.from(
{ length: currentFullMonth.days_length },
(_, i) => i + 1
);
// Create a flat array with leading zeros and trailing last week:
// [0, 0, 0, 0, 1, 2, 3, ..., 30, 31, 1, 2, 3, 4, 5, 6, 7]
const flatResultArr = [
...makeZeroArr(currentFullMonth.first_day_index),
...oneMonth,
...oneMonth // this includes extra numbers that will be trimmed
].slice(0, 7 * 6); // 7 days/week * 6 weeks
// Chunk the flat array into slices of 7:
const resultArr = [];
for (let i = 0; i < 7; i++) {
resultArr.push(flatResultArr.slice(i * 7, (i + 1) * 7));
}
return resultArr;
};
console.log(printMonthCalendar());