Javascript inheritance - asking experts oppinion on the following code - javascript

A friend of mine is attending a JavaScript course and thinks that the code he is submitting for grading is correct. However, the grader support keeps reporting it as not correct. He asked for my help and I tested the code on several IDEs and editors, online and offline, and I also got back every time a correct evaluation.
However I don't use often JavaScript ans I'm hesitating to answer my friend that he is right.
I would be most grateful if someone with more experience could tell me if the code evaluates correctly or not. Thank you.
"Determines which day of the week had the most nnumber of people visiting the pet store.
If more than one day of the week has the same, highest amount of traffic, an array containing the days (in any order) should be returned.
(ex. ["Wednesday", "Thursday"]).
If the input is null or an empty array, the function should return null.
#param week an array of Weekday objects
#return a string containing the name of the most popular day of the week if there is only one most popular day, and an array of the strings containing the names of the most popular days if there are more than one that are most popular"
function Weekday (name, traffic) {
this.name = name;
this.traffic = traffic;
}
function mostPopularDays(week) {
// IMPLEMENT THIS FUNCTION!
this.week = week;
if (typeof week !== 'object' || week === null || week === undefined || week.length === 0) {
return null;
}
var maxTr = 0;
var maxTrDay = [];
for (var i = 0; i < this.week.length; i++) {
if (this.week[i].traffic > maxTr) {
maxTrDay = [this.week[i].name];
//maxTrDay = this.week[i].name;
maxTr = this.week[i].traffic;
} else if (this.week[i].traffic === maxTr) {
//maxTrDay = [this.week[i].name];
maxTrDay.push(this.week[i].name);
} else if (this.week.length > 7) {
this.week.shift();
}
}
if (maxTrDay.length === 1) {
console.log("The most popular day of the week was:")
return maxTrDay[0];
} else if (maxTrDay > 1) {
console.log("The most popular days of the week were:")
return maxTrDay;
}
return null;
}
The test case that the grader reports as failed are the following:
1. mostPopularDays should return an array of days when more than one day has most popular traffic
I used the following lines for testing, and the output was always the last (commented) line below:
var week = [];
var sun = new Weekday('Sunday', 100); week.push(sun);
var mon = new Weekday('Monday', 90); week.push(mon);
var tue = new Weekday('Tuesday', 100); week.push(tue);
mostPopularDays(week);
// [Sunday, Tuesday]

The issue is (maxTrDay > 1) is comparing an array object with the number 1. This will be false for all array inputs except for, confusingly, e.g. ([2] > 1), but that's JS for you.
Running your code as-is with the provided driver (with added quotes to Tuesday to avoid a ReferenceError) yields the output of null.
Your friend probably means (maxTrDay.length > 1), which compares based on length and yields the correct output:
The most popular days of the week were:
=> [ 'Sunday', 'Tuesday' ]

Related

Encountering 2 outputs combined in single input

I'm working on a tuition calculator for students and updating it to reflect the current year, in changing the year, every time the #variable option is selected to Variable (inherited code, not my choice of name) the output duplicates all of the fees. I've revised the functions, and code, where is this issue arising?
(my current version with issues: https://tarleton.edu/scripts/tuitioncal/default-trial.asp)
At first I thought it was a year issue, but after reading through previous documentation, I corrected it but issue is still arising.
I'm assuming that the issue arises here and that it runs through this if/else statement twice, though the information is not changing:
$('input#submit').click(function() {
var currentDate = new Date();
var currentYear = currentDate.getFullYear(); //Currently in the middle of
the academic year, so the adjustment had to be made.
var adjustedYear = 0;
var adjustmentForYear = 0;
if ($('select#semester option:selected').hasClass('current-academic-year')){ adjustmentForYear = parseInt(-1); }
else if ($('select#semester option:selected').hasClass('future-academic-year')) { adjustmentForYear = parseInt(0); }
else if ($('select#semester option:selected').hasClass('last-year')) { adjustmentForYear = parseInt(-2); }
if ($("select#variable option:selected").val() != "variable" || $('select#classification option:selected').val() == "4")
{
//Handles ALL Guaranteed Tuition Plans and Graduate Plan
adjustedYear = (parseInt($('select#semester option:selected').val()) +
adjustmentForYear - $('select#classification option:selected').val());
}
else
{ //Handles Variable Tuition Plans for Freshmen, Sophomores, Juniors, and Seniors
adjustedYear = currentYear + adjustmentForYear;
}
I expect a non duplicated output that includes University Services fee to be $91.66, but instead see University Services fee: $991.66 AND $117.89.

Mask the last two digits of a date in JavaScript using regex

I’m trying to demonstrate how a date would look like if it was displayed with some characters masked. Specifically, something like this:
10 August 2018 => 10 August 20**
10 August 2018 => 10 August **** (and this too if possible)
I’ve spent some time looking for working examples on here but haven’t found one for this specific example. In my own experiments I only ever end up with one asterisk (10 August 19*) instead of one per character.
It all needs to happen within a textToMask.replace(regex, '*').
I know you’d never use this in production; it’s for a visual demo.
You can use padEnd method
function maskIt(str, pad = 1) {
const slicedStr = str.slice(0,pad*-1);
const masked = slicedStr.padEnd(str.length, '*');
console.log(masked);
}
maskIt("10 August 2018",2);
maskIt("10 August 2018",4);
Here's a dirt simple mask() function, that works with any string, and doesn't involve regex:
function mask(str, amt = 1) {
if (amt > str.length) {
return '*'.repeat(str.length);
} else {
return str.substr(0, str.length-amt) + '*'.repeat(amt);
}
}
console.log(mask('10 August 2018', 2));
console.log(mask('10 August 2018', 4));
console.log(mask('test', 5));
Here is a very simple function that uses a regular expression to find a given number of digits at the end of a given date and substitutes them with an equal number of asterisks.
Example:
const mask_date = (date, n) => date.replace(new RegExp(`[\\d]{${n}}$`), "*".repeat(n));
console.log(mask_date("10 August 2018", 2));
console.log(mask_date("10 August 2018", 4));
Please note that I would really like to refactor this somehow, I just don't have the time to do it right now. Check back at some point tomorrow I may have made an edit to this to make the code flow a bit better.
I am using the second version of the String.prototype.replace function that allows you to pass a function instead of a string as the second parameter. Check the link to learn more.
This is a very rough function -- I unfortunately did not have a lot of time to write this out.
// str - string to be altered, pattern - regex pattern to look through, replacement - what to replace the found pattern with, match_length - do we match the length of replacement to the length of what it is replacing?
function mask(str, pattern, replacement="*", match_length=true){
return str.replace(pattern, function(whole, group){
//init some values;
let padLength = 0, returned = '';
// if the group is not a number, then we have a regex that has a grouping. I would recommend limiting your regex patterns to ONE group, unless you edit this.
if(typeof group != 'number'){
padLength = group.length;
returned = whole.slice(0, whole.indexOf(group)) + (replacement.repeat(match_length ? padLength : 1));
}else{
padLength = whole.length;
returned = replacement.repeat(match_length ? padLength : 1);
}
return returned;
});
}
let randomBirthdayString = 'April 3 2002';
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/) );
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/, 'x') );
console.log(mask(randomBirthdayString, /\d{2}(\d{2})$/, 'x', false) );
You can use the code below.
textToMask.replace(/..$/, '**')

Comparision between 2 Object

I am working on a course registration system.I need to check for time conflicts.
Already registered courses object:
{"00001":{"days":"Monday-Tuesday","hours":"11:40-12:30*13:40-15:30"}}
this means that 00001 course is in monday 11:40-12:30 in tuesday 13:40-15:30
Courses to register object:
{"00003":{"days":"Friday","hours":"9:40-10:40"}}
I have managed to check is student already registered to course with this code:
Object.keys(registeredcoursesobject).forEach(function(key){
if( Object.keys(coursestoregisterobject).includes(key)) {
alert("You have already registered to "+key+" crn number course");
//return;
}
});
A course can be at most 2 days in a week and in 1 different time intervals(what if 2 time intervals??) which means that there will be only one "-" in days property and only one "*" in hours property.
I am new to programming and working on this for days any ideas ?
I hope this answer is still relevant for you. Here is what I have:
var registeredcoursesobject = {"00001":{"days":"Monday-Thursday","hours":"11:40-12:30*16:30-18:30"}}
var coursestoregisterobject = {"00002":{"days":"Monday-Friday","hours":"10:40-15:30*16:40-18:00"}}
var getTicks = function(timeStr) {
return new Date('1970-01-01T' + timeStr + ':00Z').getTime();
}
Object.keys(registeredcoursesobject).forEach(function(rKey){
if( Object.keys(coursestoregisterobject).includes(rKey)) {
alert("You have already registered to "+rKey+" crn number course");
return false;
};
Object.keys(coursestoregisterobject).forEach(function(cKey){
var regDays = registeredcoursesobject[rKey].days.split('-');
var regHours = registeredcoursesobject[rKey].hours.split('*');
var courseDays = coursestoregisterobject[cKey].days.split('-');
var courseHours = coursestoregisterobject[cKey].hours.split('*');
regDays.forEach(function(rDay, i) {
var rHourRange = regHours[i];
// I assume you need to check there is same date/time pain in registeredcoursesobject and coursestoregisterobject
courseDays.forEach(function(cDay, j) {
if (rDay == cDay) {
var cHourRange = courseHours[j];
// now, do you need to compare hours be equal exactly or do you need to check time overlap?
// assume you just need to ckeck hour ranges are equal, then:
if (rHourRange == cHourRange){
// means equal
alert("You have already registered to "+cKey+" crn number course on day "+cDay+" at "+cHourRange+" hours.");
return true;
}
// if you need to check range overlap
var rTime = rHourRange.split('-');
rTimeRange = [getTicks(rTime[0]), getTicks(rTime[1])];
rStartT = Math.min.apply(null, rTimeRange), rEndT = Math.max.apply(null, rTimeRange);
var cTime = cHourRange.split('-');
cTimeRange = [getTicks(cTime[0]), getTicks(cTime[1])]
cStartT = Math.min.apply(null, cTimeRange), cEndT = Math.max.apply(null, cTimeRange);
// now your rangeTime is a pair of int values, that represent time range rStartT:rEndT
// and your courseTime is a pair of int values cStartT:cEndT
// so now you just check the overlap of two integer pais.
// according to this: https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-two-integer-ranges-for-overlap#answer-3269471
if (rStartT < cEndT && cStartT < rEndT) {
alert("You have already registered to "+cKey+" crn number course on day "+cDay+" within time range "+cHourRange+" hours overlap with "+rHourRange+" time range.");
// means time ranges are overlap at some range. But I don't count the border, like "14:00-15:00" and "15:00-16:00" do not overlap
// otherwise replace < with <=
return true;
}
}
})
});
return false;
});
});
I am making some assumptions here about your task.
UPDATE: added time range check.
UPDATE: check keys equal first and values swap if start time is for some reason is bigger than end time.

Find missing quarters in time series

I am trying to see how could I fill the missing financial quarters of a time series like this in Javascript:
["2012-Q2","2012-Q4","2013-Q4","2014-Q1","2014-Q2","2014-Q3",
"2014-Q4","2015-Q1","2015-Q2","2015-Q3","2015-Q4","2016-Q1",
"2016-Q2","2016-Q3","2016-Q4","2017-Q1","2017-Q2","2017-Q3",
"2017-Q4","2018-Q1"]
I would like somehow to get a time series with the missing elements i.e. for each year I should see 4 "dates".
I don't mind ignoring the first quarter before the first element "2012-Q2" and the last 3 quarters after the last element "2018-Q1".
I know moment.js has functions like quarter() or fquarter() (via a plugin), but I am looking for something closer to the other way around. I already have the quarters (as date-strings), and I have to parse them as date objects.
I need to fill the "quarter holes" in between those input string values.
In my case I probably need to parse first those date-strings in that custom format to make them something moment could understand, but I am a bit lost. In here https://momentjs.com/docs/#/parsing/string-format/ a potential format could involve Y for years and Q for quarters, but I am not sure how to escape the literal Q inside every input date-string of that array?
Also assuming I could somehow parse all those date strings into moment objects, then I am not sure how that could help in filling the holes?
I can not find a pure javascript solution involving date types.
Another approach could be to parse those date-strings and get the year and the quarter number using substring and then manually filling the holes checking year/quarter pairs, is there anything simpler than this?
Assuming that you want a full list of quarters between the first one of your input array until the last one, you can:
parse with moment the first and the last element of your array, using moment(String, String) with 'YYYY[-Q]Q' as format parameter, see Escaping charaters section of the docs.
loop from start to end using isSameOrBefore (or other query functions) adding 1 quarter on each iteration (add(1, 'Q'))
Here a live sample:
var quarters = ["2012-Q2","2012-Q4","2013-Q4","2014-Q1","2014-Q2","2014-Q3",
"2014-Q4","2015-Q1","2015-Q2","2015-Q3","2015-Q4","2016-Q1",
"2016-Q2","2016-Q3","2016-Q4","2017-Q1","2017-Q2","2017-Q3",
"2017-Q4","2018-Q1"];
var format = 'YYYY[-Q]Q';
var start = moment(quarters[0], format);
var end = moment(quarters[quarters.length-1], format);
var results = [];
while( start.isSameOrBefore(end) ){
results.push(start.format(format));
start.add(1, 'Q');
}
console.log(results);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
Why not just make a function that returns the quarters from a particular range?
function getQuarters(startYear, endYear){
var times = [];
for(var i = startYear; i <= endYear; i++){
times.push(i + "-Q1");
times.push(i + "-Q2");
times.push(i + "-Q3");
times.push(i + "-Q4");
}
return times;
}
Calling:
getQuarters(2017,2017);
Returns:
["2017-Q1", "2017-Q2", "2017-Q3", "2017-Q4"]
Assuming you want to get an array with the missing values, you could take a start quarter and cehck against the given data for either pushing the quartal or incremet the index of the array.
function incQ(time) {
time[1]++;
if (time[1] === 5) {
time[0]++;
time[1] = 1;
}
}
var quarters = ["2012-Q2", "2012-Q4", "2013-Q4", "2014-Q1", "2014-Q2", "2014-Q3", "2014-Q4", "2015-Q1", "2015-Q2", "2015-Q3", "2015-Q4", "2016-Q1", "2016-Q2", "2016-Q3", "2016-Q4", "2017-Q1", "2017-Q2", "2017-Q3", "2017-Q4", "2018-Q1"],
actual = quarters[0].split('-Q'),
missing = [],
i = 0;
while (i < quarters.length) {
if (actual.join('-Q') !== quarters[i]) {
missing.push(actual.join('-Q'));
} else {
i++;
}
incQ(actual);
}
console.log(missing);

Read a file with latest Date from a folder using JQuery

I already have a folder, with the files in it with names below in a specific format i.e. MODEL_RELEASEDATE
File names in the folder named Smartphone
SmartphoneA_11122012
SmartphoneA_01022013
SmartphoneA_09102013
SmartphoneA_10072012
SmartphoneA_12042012
**SmartphoneB_08282013**
SmartphoneB_04152013
SmartphoneB_08282012
SmartphoneB_01062013
.
.
.
.
and so on
I want to write a jquery code where I can use a specific keyword from format, from above list, I will pass the value SmartphoneA and I should be able to read the file with the latest release date. Same as in case when I pass the keyword SmartphoneB.
If I pass k/w SmartphoneB, result should be served from file highlighted above, i.e. SmartphoneB_08282013
my current code reads the file name only with specific k/w. I have few alterations to be made.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
var metaKeywords=$('meta[name=keywords]').attr("content");//this utility works based upon the keywords on the pages.
var reqdKeyword = new Array();
reqdKeyword = metaKeywords.split(",");
var randKeyword = reqdKeyword[Math.floor(Math.random() * reqdKeyword.length)];
var cdnUrl = "http://abc.com/xyz/mobiles/";
var jsnUrl = ".json?callback=showDetail";
var finalUrl= cdnUrl.concat(randKeyword.trim()).concat(jsnUrl);
/*
Rest of the code goes here
*/
</script>
The cool thing about dates is that you can easily sort them if you have the date in "descending" order (i.e., year month day hour second). Using that, we can go through your files to grab just the ones that start with the right prefix, then easily grab the latest one:
var filenames = [
'SmartphoneA_11122012',
'SmartphoneA_01022013',
'SmartphoneA_09102013',
'SmartphoneA_10072012',
'SmartphoneA_12042012',
'SmartphoneB_08282013',
'SmartphoneB_04152013',
'SmartphoneB_08282012',
'SmartphoneB_01062013'
],
whichPhone = 'SmartphoneB', // Dummy value, this would come from user interaction or whatever
possibleFiles = [];
// This goes through your list of filenames and picks out just the ones that match `whichPhone`, then puts them into another array containing a "cleaned-up" date and some other metadata-esque stuff
for (var i = 0, j = filenames.length; i < j; i++) {
var filename = filenames[i];
if (filename.indexOf(whichPhone) > -1) {
possibleFiles.push({
index: i,
filename: filename,
date: parseInt(filename.split('_')[1].replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}), 10)
});
}
}
// Now we go through the `possibleFiles` and figure out which one has the latest date
var latestFileDate = 0,
theActualFilenameYouWantFinally;
for (var i = 0, j = possibleFiles.length; i < j; i++) {
var possibleFile = possibleFiles[i];
if (possibleFile.date > latestFileDate) {
latestFileDate = possibleFile.date;
theActualFilenameYouWantFinally = filenames[possibleFile.index];
}
}
// And, finally, your result
console.log(theActualFilenameYouWantFinally);
EDIT: I didn't use jQuery for this answer because meh, you don't really need jQuery for things like this. Don't get me wrong, John Resig is brilliant, and I use jQuery in almost everything, but for loops are damned fast and easy to work with, and stuff like this isn't really jQuery's strong suit anyhow.
You will need a server-side code to return you a list of URIs (file names), then you can write JavaScript code to parse it (but in this case it is probably better if your server-side code will return the right name right away based on query string). In the worst case scenario you can place a dir.txt file on the server which will be listing all the files in that folder and e.g. run cron job to update it as needed.
jQuery will have no way to list remote files on the server unless your server supports it in one way or another.
Update
Once you have the file you need:
a) tokenize it into an array, e.g. like this
var names = dir.split("\n");
b) leave only strings starting with keyword and cut keyword off
names = $(names).map(function(n,i) {
return (n.indexOf(keyword) == 0) ? n.split('_')[1] : null;
}).get();
now you have an array like this ['11122012', '01022013', ...]
c) find max date in this array
var dateNum = Math.max.apply( null,
$.map(names,function(n,i){ return parseInt(
n.replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}))
}) );
var maxDate = dateNum.toString().replace(/(\d{4})(\d{2})(\d{2})/,
function (match, year, month, day) { return month + day + year; }
);
var fileName = keyword + "_" + maxDate;
voila, your fileName contains the name with max date.
There are other ways of doing it, e.g. really parsing the date into Date object. Also, you can simply iterate your files once, without array mapping and Math.max() iterator. As the amount of code wins over speed here, to find the optimal one depends on where you could re-use its bits and pieces without compromising maintainability.
http://jsfiddle.net/Exceeder/VLB2E/

Categories

Resources