* fix: remove isHidden key from tool template * fix: removed isHidden key from English challenges * fix: remove isHidden key from Chinese challenges
8.9 KiB
8.9 KiB
id, title, challengeType
id | title | challengeType |
---|---|---|
5d79253a98bd9fdf7ce68d0a | Part 137 | 0 |
Description
We've used recursion in range
, but recursion can have performance issues in JavaScript. If performance is an issue, you should try to use a higher order function like reduce
, and if you can't do that, you'll probably have to use a for/while loop.
While we don't expect the user to enter particularly large numbers so that performance is an issue, we're going to refactor range
as an exercise.
Replace the body of range
with start
.
Instructions
Tests
tests:
- text: See description above for instructions.
testString: assert(/constrange=\(start,end\)=>start(;|const)/.test(code.replace(/\s/g, "")));
Challenge Seed
<script>
const infixToFunction = {
"+": (x, y) => x + y,
"-": (x, y) => x - y,
"*": (x, y) => x * y,
"/": (x, y) => x / y
};
const infixEval = (str, regex) =>
str.replace(regex, (_, arg1, fn, arg2) =>
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
);
const highPrecedence = str => {
const regex = /([0-9.]+)([*\/])([0-9.]+)/;
const str2 = infixEval(str, regex);
return str === str2 ? str : highPrecedence(str2);
};
const isEven = num => num % 2 === 0;
const sum = nums => nums.reduce((a, x) => a + x);
const average = nums => sum(nums) / nums.length;
const median = nums => {
const sorted = nums.slice().sort((x, y) => x - y);
const length = sorted.length;
const middle = sorted.length / 2 - 1;
return isEven(length)
? average([sorted[middle], sorted[middle + 1]])
: sorted[middle + 0.5];
};
const spreadsheetFunctions = {
"": x => x,
random: ([x, y]) => Math.floor(Math.random() * y + x),
increment: nums => nums.map(x => x + 1),
firsttwo: arr => arr.slice(0, 2),
lasttwo: arr => arr.slice(-2),
even: nums => nums.filter(isEven),
sum,
average,
median,
has2: arr => arr.includes(2),
nodups: arr => arr.reduce((a, x) => a.includes(x) ? a : a.concat(x), []),
range: arr => range(...arr),
someeven: arr => arr.some(isEven),
everyeven: arr => arr.every(isEven)
};
const applyFn = str => {
const noHigh = highPrecedence(str);
const infix = /([0-9.]+)([+-])([0-9.]+)/;
const str2 = infixEval(noHigh, infix);
const regex = /([a-z]*)\(([0-9., ]*)\)(?!.*\()/i;
const toNumberList = args => args.split(",").map(parseFloat);
const applyFunction = (fn, args) =>
spreadsheetFunctions[fn.toLowerCase()](toNumberList(args));
return str2.replace(
regex,
(match, fn, args) =>
spreadsheetFunctions.hasOwnProperty(fn.toLowerCase()) ? applyFunction(fn, args) : match
);
};
const range = (start, end) =>
start > end ? [] : [start].concat(range(start + 1, end));
const charRange = (start, end) =>
range(start.charCodeAt(0), end.charCodeAt(0)).map(x =>
String.fromCharCode(x)
);
const evalFormula = (x, cells) => {
const idToText = id => cells.find(cell => cell.id === id).value;
const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi;
const rangeFromString = (n1, n2) => range(parseInt(n1), parseInt(n2));
const elemValue = n => c => idToText(c + n);
const addChars = c1 => c2 => n => charRange(c1, c2).map(elemValue(n));
const varRangeExpanded = x.replace(rangeRegex, (_, c1, n1, c2, n2) =>
rangeFromString(n1, n2).map(addChars(c1)(c2))
);
const varRegex = /[A-J][1-9][0-9]?/gi;
const varExpanded = varRangeExpanded.replace(
varRegex,
match => idToText(match.toUpperCase())
);
const functionExpanded = applyFn(varExpanded);
return functionExpanded === x
? functionExpanded
: evalFormula(functionExpanded, cells);
};
window.onload = () => {
const container = document.getElementById("container");
const createLabel = name => {
const label = document.createElement("div");
label.className = "label";
label.textContent = name;
container.appendChild(label);
};
const letters = charRange("A", "J");
letters.forEach(createLabel);
range(1, 99).forEach(x => {
createLabel(x);
letters.forEach(y => {
const input = document.createElement("input");
input.type = "text";
input.id = y + x;
input.onchange = update;
container.appendChild(input);
});
});
};
const update = event => {
const element = event.target;
const value = element.value.replace(/\s/g, "");
if (!value.includes(element.id) && value[0] === "=") {
element.value = evalFormula(
value.slice(1),
Array.from(document.getElementById("container").children)
);
}
};
</script>
Before Test
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spreadsheet</title>
<style>
#container {
display: grid;
grid-template-columns: 50px repeat(10, 200px);
grid-template-rows: repeat(11, 30px);
}
.label {
background-color: lightgray;
text-align: center;
vertical-align: middle;
line-height: 30px;
}
</style>
</head>
<body>
<div id="container">
<div></div>
</div>
After Test
</body>
</html>
Solution
<script>
const infixToFunction = {
"+": (x, y) => x + y,
"-": (x, y) => x - y,
"*": (x, y) => x * y,
"/": (x, y) => x / y
};
const infixEval = (str, regex) =>
str.replace(regex, (_, arg1, fn, arg2) =>
infixToFunction[fn](parseFloat(arg1), parseFloat(arg2))
);
const highPrecedence = str => {
const regex = /([0-9.]+)([*\/])([0-9.]+)/;
const str2 = infixEval(str, regex);
return str === str2 ? str : highPrecedence(str2);
};
const isEven = num => num % 2 === 0;
const sum = nums => nums.reduce((a, x) => a + x);
const average = nums => sum(nums) / nums.length;
const median = nums => {
const sorted = nums.slice().sort((x, y) => x - y);
const length = sorted.length;
const middle = sorted.length / 2 - 1;
return isEven(length)
? average([sorted[middle], sorted[middle + 1]])
: sorted[middle + 0.5];
};
const spreadsheetFunctions = {
"": x => x,
random: ([x, y]) => Math.floor(Math.random() * y + x),
increment: nums => nums.map(x => x + 1),
firsttwo: arr => arr.slice(0, 2),
lasttwo: arr => arr.slice(-2),
even: nums => nums.filter(isEven),
sum,
average,
median,
has2: arr => arr.includes(2),
nodups: arr => arr.reduce((a, x) => a.includes(x) ? a : a.concat(x), []),
range: arr => range(...arr),
someeven: arr => arr.some(isEven),
everyeven: arr => arr.every(isEven)
};
const applyFn = str => {
const noHigh = highPrecedence(str);
const infix = /([0-9.]+)([+-])([0-9.]+)/;
const str2 = infixEval(noHigh, infix);
const regex = /([a-z]*)\(([0-9., ]*)\)(?!.*\()/i;
const toNumberList = args => args.split(",").map(parseFloat);
const applyFunction = (fn, args) =>
spreadsheetFunctions[fn.toLowerCase()](toNumberList(args));
return str2.replace(
regex,
(match, fn, args) =>
spreadsheetFunctions.hasOwnProperty(fn.toLowerCase()) ? applyFunction(fn, args) : match
);
};
const range = (start, end) => start
const charRange = (start, end) =>
range(start.charCodeAt(0), end.charCodeAt(0)).map(x =>
String.fromCharCode(x)
);
const evalFormula = (x, cells) => {
const idToText = id => cells.find(cell => cell.id === id).value;
const rangeRegex = /([A-J])([1-9][0-9]?):([A-J])([1-9][0-9]?)/gi;
const rangeFromString = (n1, n2) => range(parseInt(n1), parseInt(n2));
const elemValue = n => c => idToText(c + n);
const addChars = c1 => c2 => n => charRange(c1, c2).map(elemValue(n));
const varRangeExpanded = x.replace(rangeRegex, (_, c1, n1, c2, n2) =>
rangeFromString(n1, n2).map(addChars(c1)(c2))
);
const varRegex = /[A-J][1-9][0-9]?/gi;
const varExpanded = varRangeExpanded.replace(
varRegex,
match => idToText(match.toUpperCase())
);
const functionExpanded = applyFn(varExpanded);
return functionExpanded === x
? functionExpanded
: evalFormula(functionExpanded, cells);
};
window.onload = () => {
const container = document.getElementById("container");
const createLabel = name => {
const label = document.createElement("div");
label.className = "label";
label.textContent = name;
container.appendChild(label);
};
const letters = charRange("A", "J");
letters.forEach(createLabel);
range(1, 99).forEach(x => {
createLabel(x);
letters.forEach(y => {
const input = document.createElement("input");
input.type = "text";
input.id = y + x;
input.onchange = update;
container.appendChild(input);
});
});
};
const update = event => {
const element = event.target;
const value = element.value.replace(/\s/g, "");
if (!value.includes(element.id) && value[0] === "=") {
element.value = evalFormula(
value.slice(1),
Array.from(document.getElementById("container").children)
);
}
};
</script>