I recently took a coding test for a promotion at work. This was one of the tasks I really struggled with and was wondering what is the best way to do this. I used a load of
Here's my attempt. Added inline comments with explanations.
// think of the result of the form {h1}{h2}:{ms}
function generate(a, b, c, d) {
const digits = [a, b, c, d];
// extract possible starting digits
const possibleH1s = [2, 1, 0].filter(digit => digits.includes(digit));
// check result, starting from the highest possible h1 digit
// if digits doesn't contains any of [2,1,0], we're done
for (const h1 of possibleH1s) {
// extract the remaining digits after h1
const withoutH1 = removeFrom(digits, h1);
// determine all possible h2 digits based on the h1 digit
const possibleH2s = h1 === 2
? [3,2,1,0]
: [9,8,7,6,5,4,3,2,1,0];
// find the highest possible h2 digit (works because array of possible digits above is in descending order)
// if none exist, loop iteration is done
const h2 = possibleH2s.find(d => withoutH1.includes(d));
if (typeof h2 !== 'number') {
continue;
}
// remove h2 so we can search for the remaining ms digits
const [possibleMS1, possibleMS2] = removeFrom(withoutH1, h2);
// build the two possible combinations for ms
const possibleMs = [
Number(`${possibleMS1}${possibleMS2}`),
Number(`${possibleMS2}${possibleMS1}`)
];
// determine the min and max ms value
const maxMs = Math.max(...possibleMs);
const minMs = Math.min(...possibleMs);
// find the largest valid ms value
// if none exist, loop iteration is done
const ms = maxMs < 60 ? maxMs : minMs < 60 ? minMs : undefined;
if (typeof ms !== 'number') {
continue;
}
// yay, time
return `${h1}${h2}:${padWithZero(ms)}`;
}
return 'NOT POSSIBLE';
}
// returns a new array by removing a single element
// that is equal to `val` from the given array
// (performs better than splice cause if doesn't do array shift)
function removeFrom(arr, val) {
const newArr = [];
for (let i = 0, l = arr.length, found = false; i < l; i++) {
if (arr[i] !== val || found) {
newArr.push(arr[i]);
} else {
found = true;
}
}
return newArr;
}
function padWithZero(digit) {
return digit < 10 ? `0${digit}` : `${digit}`;
}
/* --------------- Tests --------------------- */
const speedTest = (times = 10000) => {
let counter = times;
const start = performance.now();
while (counter--) {
const A = randNum();
const B = randNum();
const C = randNum();
const D = randNum();
generate(A, B, C, D);
if (counter == 0) {
const ms = performance.now() - start;
console.log(`${times} times to run generate took ${ms} ms`);
}
}
}
const randNum = () => Math.floor(Math.random() * (9 - 0 + 1)) + 0;
const accuracyTest = () => {
console.assert(generate(1,7,2,7) === '17:27');
console.assert(generate(0,0,2,9) === '20:09');
console.assert(generate(6,5,2,0) === '20:56');
console.assert(generate(3,9,5,0) === '09:53');
console.assert(generate(7,6,3,8) === 'NOT POSSIBLE');
console.assert(generate(0,0,0,0) === '00:00');
console.assert(generate(9,9,9,9) === 'NOT POSSIBLE');
console.assert(generate(1,2,3,4) === '23:41');
console.log('All good!');
}
speedTest();
accuracyTest();