Problem overview
The method clampAll receives an array of integers nums and two limits, low and high, and returns every number moved inside the limits, in the same order. A number below low becomes low, a number above high becomes high, and any other number stays as it is. The limits are never reversed: low is at most high. The task bans the built-in min and max, so the comparing is done by hand.
For [12, -3, 7, 25] with limits 0 and 20, the result is [12, 0, 7, 20]: -3 is below 0, 25 is above 20, and the others are inside. For [3, 9, 6] with both limits equal to 6, every number becomes 6.
Approach: one helper for one number
The lesson splits the work into two methods. The helper, clamp, solves the problem for a single number: it takes x and the two limits and returns x moved inside them. The main method, clampAll, only loops over the array and calls the helper for each number.
That split keeps both pieces small. The helper has no loop, and the loop has no if. You can test the helper alone, for example clamp(25, 0, 20) is 20, clamp(-3, 0, 20) is 0 and clamp(7, 0, 20) is 7.
Step by step
- In
clamp, check the low side. Ifx < low, returnlow. - Check the high side. If
x > high, returnhigh. - Return
x. Only a number between the limits gets here, and it stays as it is. Noelseis needed, because eachreturnends the method. - In
clampAll, createclamped, an emptynumber[]. - Loop over
numswithfor (const num of nums). - Push the helper's answer for
numontoclamped, calling the helper asthis.clamp(num, low, high). - Return
clampedafter the loop.
The solution in TypeScript
class Solution {
clamp(x: number, low: number, high: number): number {
if (x < low) {
return low;
}
if (x > high) {
return high;
}
return x;
}
clampAll(nums: number[], low: number, high: number): number[] {
let clamped: number[] = [];
for (const num of nums) {
clamped.push(this.clamp(num, low, high));
}
return clamped;
}
}
The part specific to TypeScript is how one method calls another:
this.is required. Inside a class, a method is reached throughthis. Writing plainclamp(num, low, high)looks for a function or variable calledclampoutside the class. The compiler reports "Cannot find name 'clamp'" and suggeststhis.clamp, and the JavaScript it still writes stops withclamp is not definedwhen that line runs.- The result is a new array.
numsis not modified.pushadds toclamped, which starts empty. - Parameter types are not checked at run time. The annotations help the compiler, but the compiled JavaScript does not enforce them.
Tracing the first example
With limits 0 and 20, clampAll calls the helper once per number, and the helper answers like this:
| num | helper's answer | why |
|---|---|---|
| 12 | 12 | inside the limits |
| -3 | 0 | below low |
| 7 | 7 | inside the limits |
| 25 | 20 | above high |
Pushing those answers in order builds [12, 0, 7, 20]. The input array is still [12, -3, 7, 25] afterwards, because the method pushes into a separate array.
Why a helper at all
The comparing could be written directly inside the loop, with an if and an else if. The helper gives the rule a name, clamp, and makes the loop read as plain English: for each number, push its clamped value. When a program needs the same rule in a second place, it calls the helper again instead of copying the comparisons. A bug in the rule is then fixed once.
Another way
Array's map builds the new array for you, so the loop and the push disappear. The arrow function keeps this from the surrounding method, so the helper is still called as this.clamp:
clampAll(nums: number[], low: number, high: number): number[] {
return nums.map((num) => this.clamp(num, low, high));
}
On the first example it returns [12,0,7,20], the same as the loop. The lesson uses the explicit loop because it shows each step.
The language does offer a one-line form, Math.min(Math.max(x, low), high), which gives 20, 0 and 7 for 25, -3 and 7 with limits 0 and 20. The task asks you not to use it, so that you practise the comparisons yourself and see why the order of the two tests does not matter when low is at most high: a number cannot be both below low and above high.
Edge cases and common mistakes
- Equal limits. With
low == highevery number is mapped to that value, because each one is either below, above or already equal to it. - Negative limits.
[-8, -1, 4]with limits -5 and 5 gives[-5, -1, 4]. The comparisons work the same for negative numbers. - Numbers exactly on a limit. They fail both tests (
x < lowandx > highare both false) and are returned unchanged. Using<=or>=would still give the right value, only through a longer path. - Returning inside the loop. A
returnplaced inside theforwould send back just the first number's array. - Swapped limits. If the limits were reversed,
clamp(5, 10, 0)would return 10, because the low test fires first. The task guarantees that never happens.
Testing
[12, -3, 7, 25], 0, 20 gives[12, 0, 7, 20].[-8, -1, 4], -5, 5 gives[-5, -1, 4].[3, 9, 6], 6, 6 gives[6, 6, 6].- The helper alone:
clamp(0, 0, 20)gives0andclamp(20, 0, 20)gives20, so a number sitting exactly on a limit is returned as it is.
