Start learning free

LESSON 246 OF 677 · HELPER FUNCTIONS

Clamp All in Scala: A Helper Method Called in a Loop

Practice Read the full explanation

You get an array of integers nums and two limits, low and high. Return every number moved inside the limits, in the same order.

A number below low becomes low. A number above high becomes high. Any other number stays as it is.

The work is split between two functions. The first one is a helper. It gets one number and the two limits. It returns that number moved inside them. The second one is the function that is graded. It calls the helper on every number.

Don't use a built-in min, max or clamp function. The helper does the comparing.

 

Example 1:

Input: nums = [12, -3, 7, 25], low = 0, high = 20
Output: [12, 0, 7, 20]
Explanation: -3 is below 0, so it becomes 0.
25 is above 20, so it becomes 20.
12 and 7 are already inside the limits.

Example 2:

Input: nums = [-8, -1, 4], low = -5, high = 5
Output: [-5, -1, 4]
Explanation: The limits can be negative too.
-8 is below -5, so it becomes -5.
-1 and 4 stay as they are.

Example 3:

Input: nums = [3, 9, 6], low = 6, high = 6
Output: [6, 6, 6]
Explanation: Both limits are 6, so every number becomes 6.

 

Constraints:

  • nums has at least one number.
  • Every number is between -1000 and 1000.
  • low and high are between -1000 and 1000.
  • low is never greater than high.
STEP 1 OF 7
    Ctrl + Enter to check

    SCALA · HELPER FUNCTIONS

    Clamp All in Scala, explained

    Problem overview

    The method clampAll gets an Array[Int] called nums and two limits, low and high, and returns an ArrayBuffer[Int] in which every number is 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. Built-in min, max and clamp functions are not allowed, so the comparing is done by hand.

    For nums = [12, -3, 7, 25] with limits 0 and 20, the answer is [12, 0, 7, 20]. With [-8, -1, 4] and limits -5 and 5 it is [-5, -1, 4]. With [3, 9, 6] and both limits equal to 6, every number becomes 6.

    Approach

    The work is split in two. A small helper method, clamp, deals with one number: it knows the rule. The method clampAll knows only how to go through the array and call the helper once per number. Each method then does one job, and each is easy to read and to test on its own.

    Why split the work

    The rule "move a number inside the limits" is one idea, and it has a name, clamp. Once it is a method of its own, the loop in clampAll reads like the task: for each number, add the clamped number. If the rule were wrong, you would fix it in one place. If you later needed to clamp a single number somewhere else, you could call the same method. The helper takes everything it needs as parameters (x, low and high) and gives back one answer, so you can check it alone before the loop exists.

    Step by step

    The helper

    1. If x is less than low, return low.
    2. If x is greater than high, return high.
    3. Otherwise return x. Only a number between the limits reaches this line, so no else is needed.

    The main method

    1. Create an empty ArrayBuffer[Int] called clamped. It is a val, but the buffer can still grow.
    2. Loop over the numbers with for (num <- nums).
    3. Append clamp(num, low, high) to clamped with +=. The loop needs no if of its own.
    4. After the loop, return clamped.

    The solution in Scala

    class Solution {
        def clamp(x: Int, low: Int, high: Int): Int = {
            if (x < low) {
                return low
            }
            if (x > high) {
                return high
            }
            return x
        }
    
        def clampAll(nums: Array[Int], low: Int, high: Int): ArrayBuffer[Int] = {
            val clamped = ArrayBuffer[Int]()
            for (num <- nums) {
                clamped += clamp(num, low, high)
            }
            return clamped
        }
    }
    

    Both methods live in the same class, so clampAll calls clamp by its plain name. The array and the buffer are different types: nums is a fixed-size Array, and the answer is an ArrayBuffer that grows one number at a time.

    How the helper treats the first example

    With limits 0 and 20, calling the helper on 12, -3, 7 and 25 returns 12, 0, 7 and 20. The first and third calls reach the final return x. The second stops at the first check, and the fourth stops at the second. Each number takes exactly one of the three exits.

    Testing

    The three examples return 12 0 7 20, -5 -1 4 and 6 6 6 (the tests print lists as values separated by spaces). The helper alone gives clamp(-3, 0, 20) = 0.

    Another way

    In Scala an if is an expression, so the helper can be written without return, as a chain whose last branch is the value:

    def clamp(x: Int, low: Int, high: Int): Int =
        if (x < low) low
        else if (x > high) high
        else x
    

    It gives the same answers: on [12, -3, 7, 25] with limits 0 and 20 it produces 12 0 7 20. The lesson's version with early returns says the same thing one case at a time, which is easier to follow when you are starting out.

    The loop could be replaced by nums.map(clamp(_, low, high)). Note that map on an Array gives back an Array, not an ArrayBuffer, and the lesson's method has to return a buffer. Wrapping the result with ArrayBuffer.from(...) converts it. The explicit loop avoids that detour and shows each step.

    Edge cases and common mistakes

    • Equal limits. When low and high are the same, the first check catches numbers below it, the second catches numbers above it, and a number equal to both limits falls through and is returned as it is.
    • Limits in the wrong order. The statement promises low is never greater than high. If it were, the two checks could disagree and the helper would no longer have a sensible answer, so the method does not try to handle it.
    • Negative limits. The comparisons work the same way: -8 is less than -5.
    • Writing the comparisons in the loop. It works, but then the loop does the helper's job, and the point of the lesson is the split.
    • Returning inside the loop. A return in the loop body would send back the first number alone. The buffer is returned after the loop.
    • Using <= in the checks. It changes nothing in the result, because a number equal to a limit is returned as it is either way, but < and > match the rule as it is stated.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free