Home > Software engineering >  most-frequent-weekdays problem in javascript
most-frequent-weekdays problem in javascript

Time:03-30

Doing the best research, I couldn't find the answer in JavaScript, But I found this solution that works perfectly in python

import datetime
def most_frequent_days(year):
    days = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')
    most = sorted(list(set([datetime.date(year, 1, 1).weekday() ,datetime.date(year, 12, 31).weekday()])))
    return [days[i] for i in most]

print(most_frequent_days(212))

Now trying to convert this into JavaScript, you need to know python (I know how to deal with python) the best thing I come up with

const mostFrequentDays = year => {
  function getDayOfWeek(date) {
    const dayOfWeek = new Date(date).getDay();    
    return isNaN(dayOfWeek) ? null : 
      ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][dayOfWeek];
  }
  //let days = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]
  let most = [getDayOfWeek(`${year}-1-1`), getDayOfWeek(`${year}-12-31`)].sort()
  let mySet = [...new Set(most)]
  //let sorted = mySet;
  let i = 0;
  let data = [];
  while (i < mySet.length) {
      data = [ ...data, mySet[i] ]
    i  ;
  }
  return data;
};

Now this works in JS, however when I try to use the function I built mostFrequentDays(212) I don't get the expected output

**You are given a year as an integer. Return the most frequent day(s) of the week in that year. The resulting list of days should be sorted by the order of days in week starting from Monday (e. g. ['Monday', 'Tuesday']). **

Tests

it("should handle basic tests", () => {
    assert.deepEqual(mostFrequentDays(2427), ["Friday"]);
    assert.deepEqual(mostFrequentDays(2185), ["Saturday"]);
    assert.deepEqual(mostFrequentDays(1084), ["Tuesday", "Wednesday"]);
    assert.deepEqual(mostFrequentDays(1167), ["Sunday"]);
    assert.deepEqual(mostFrequentDays(1216), ["Friday", "Saturday"]);
    assert.deepEqual(mostFrequentDays(1492), ["Friday", "Saturday"]);
    assert.deepEqual(mostFrequentDays(1770), ["Monday"]);
    assert.deepEqual(mostFrequentDays(1785), ["Saturday"]);
    assert.deepEqual(mostFrequentDays(212), ["Wednesday", "Thursday"]);
});

A lot of them works when I convert the python code to JS except the last one because the JS Date doesn't work on year 212

Please help me make a function that can pass all the tests, there are a lot of python versions of the solution but the one I used is the easy one, and in python, that code works because the DateTime in python work on a date like 212. Or maybe if you know a better version that's not originally from python, how would you implement a solution for JS

Thank you, Best regards.

CodePudding user response:

You need to define "doesn't work".

A non–leap year has 365 days, which is 52 weeks plus one day. So whichever day is the first day of the year will have 53 occurrences and all the others will have 52. So the most frequent is just the weekday of 1 January.

For a leap year, the first and second day will have 53 occurrences and the others 52. e.g. 1 Jan 2018 was Monday, as was 31 December, so there were 53 Mondays and 52 of the others. 1 Jan 2020 was Wednesday and a leap year, 31 Dec was Thursday so 53 Wednesdays and Thursdays and 52 of the rest.

Of course a random range of dates will make life a little more difficult.

A function to implement the above is:

function mostFrequentDaysOfYear(year = new Date().getFullYear()) {
  // 1 Jan
  let d = new Date(year, 0);
  // Weekday name for 1 Jan
  let mostFrequent = [d.toLocaleString('en',{weekday:'long'})];
  let isLeap = new Date(year, 1, 29).getDate() == 29;
  // If leap year, add next day's name too
  if (isLeap) {
    d.setDate(d.getDate()   1);
    mostFrequent.push(d.toLocaleString('en',{weekday:'long'}))
  }

  return mostFrequent;
}

// Examples
[2018, 2020, 2022, 212].forEach(year => console.log(
  `${year}: ${mostFrequentDaysOfYear(year)}`
));

Another algorithm (which is what the PHP code is doing) is to check if 1 Jan and 31 Dec are the same day. If they are, return that day. If not, return both days.

The only sorting that's required is where a leap year starts on Sunday. The default return is [Sunday, Monday] but the requirement is for [Monday, Sunday] in that particular case.

So if 1 Jan is a Sunday (day 0) reverse the day list, e.g.

function mostFrequentDaysOfYear(year = new Date().getFullYear()) {
  let dayName = d => d.toLocaleString('en',{weekday:'long'});
  // 1 Jan
  let d = new Date(year, 0, 1);
  let d0 = dayName(d);
  // 31 Dec
  let d1 = dayName(new Date(year, 11, 31));
  let result = d0 == d1? [d0] : [d0, d1];
  // If d0 is Sunday, reverse result
  return d.getDay()? result : result.reverse();
}

[2427, // Friday
 2185, // Saturday
 1084, // Tuesday, Wednesday
 1167, // Sunday
 1216, // Friday, Saturday
 1492, // Friday, Saturday
 1770, // Monday
 1785, // Saturday
 2040, // Monday, Sunday - leap year starting on Sun
 212   // Wednesday, Thursday
].forEach(year => console.log(
  `${year}: ${mostFrequentDaysOfYear(year)}`
));

  • Related