Spent some time to compare the three proposals to check behavior against invalid inputs and also check total execution time
var reference = ["mon", "tues", "wed", "thur", "fri", "sat", "sun"];
var testcases = [
["mon", "tues", "wed", "thur", "fri", "sat", "sun"],
["mon", "tues", "fri", "sat", "sun"],
["mon", "wed", "fri", "sun"],
["mon", "dupa", "test", "halo", "fri", "sat", "sun"],
["sat", "", "fri", "sat", "sun"],
["wed", "mon", "fri", "tues"],
[""],
[]];
// https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function Marcin(ct, ref) {
var i0 = 0;
var i1 = 0;
var state = 0; // 0 initial 1 later initial 2 inside
var result = "";
var len = 0;
if (ct.length === 0)
return "";
while(i0 <= ct.length && i1 <= ref.length) {
switch(state) {
case 0:
case 1:
while(i1<ref.length && ct[i0] != ref[i1++]);
if(state == 1)
result += ' & ';
result += capitalizeFirstLetter(ct[i0++]);
state = 2;
len = 0;
break;
case 2:
if((i0 >= ct.length || i1 >= ref.length) || (ct[i0] != ref[i1])) {
i0--;
if (len)
result += '-' + capitalizeFirstLetter(ct[i0]);
state = 1;
}
i0++;
i1++;
len++;
break;
}
}
return result;
}
var dayNo = {};
reference.forEach((d, i) => dayNo[d] = i);
//// I modified it here to move building of hash outside of the function
function Nina(data, days) {
var result;
result = data
.reduce((r, d, i, dd) => {
if ((dayNo[dd[i - 1]] + 1) % 7 === dayNo[d]) {
r[r.length - 1][1] = d;
} else {
r.push([d]);
}
return r;
}, [])
.map(r => r.join(' - '))
.join(' & ');
return result;
}
function Jonas(arr, days){
var result = [ [] ], current = result [0];
for(var day of arr){
if( days.indexOf( current[current.length-1] ) +1 === days.indexOf( day) ){
current.push(day);
}else{
current = [day];
result.push( current);
}
}
return result
.filter(el => el.length)
.map(el=> el.length > 1?el[0] +"-"+ el.pop():el[0])
.join(" & ");
}
var functions=[Marcin, Nina, Jonas];
var vlog = ""
function vlogger(x) {vlog += x + "\n"};
functions.forEach((cv) => {
vlogger("testing function " + cv.name);
testcases.forEach((tc) => {
vlogger("* input " + tc);
vlogger("* outpt " + cv(tc,reference));
});
var n = 100000;
var d1 = new Date();
while(n--) {
cv(testcases[1], reference);
}
var d2 = new Date();
vlogger("* time " + (d2 - d1));
});
console.log(vlog);
Surprisingly adding hashtable did not help much with overall performance. Even once I have modified the original code to have the hash built only once. Solutions differ also how they behave against out-of-order and out of place inputs.
testing function Marcin
* input mon,tues,wed,thur,fri,sat,sun
* outpt Mon-Sun
* input mon,tues,fri,sat,sun
* outpt Mon-Tues & Fri-Sun
* input mon,wed,fri,sun
* outpt Mon & Wed & Fri & Sun
* input mon,dupa,test,halo,fri,sat,sun
* outpt Mon & Dupa
* input sat,,fri,sat,sun
* outpt Sat &
* input wed,mon,fri,tues
* outpt Wed & Mon
* input
* outpt
* input
* outpt
* time 62
testing function Nina
* input mon,tues,wed,thur,fri,sat,sun
* outpt mon - sun
* input mon,tues,fri,sat,sun
* outpt mon - tues & fri - sun
* input mon,wed,fri,sun
* outpt mon & wed & fri & sun
* input mon,dupa,test,halo,fri,sat,sun
* outpt mon & dupa & test & halo & fri - sun
* input sat,,fri,sat,sun
* outpt sat & & fri - sun
* input wed,mon,fri,tues
* outpt wed & mon & fri & tues
* input
* outpt
* input
* outpt
* time 170
testing function Jonas
* input mon,tues,wed,thur,fri,sat,sun
* outpt mon-sun
* input mon,tues,fri,sat,sun
* outpt mon-tues & fri-sun
* input mon,wed,fri,sun
* outpt mon & wed & fri & sun
* input mon,dupa,test,halo,fri,sat,sun
* outpt mon & dupa & test & halo & fri-sun
* input sat,,fri,sat,sun
* outpt sat & & fri-sun
* input wed,mon,fri,tues
* outpt wed & mon & fri & tues
* input
* outpt
* input
* outpt
* time 142