Start learning free

LESSON 249 OF 679 · HELPER FUNCTIONS

Clamp All in Rust: A Helper Function and 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

    RUST · HELPER FUNCTIONS

    Clamp All in Rust, explained

    Problem overview

    This lesson has two functions. The helper clamp receives one number x and two limits, low and high, and returns x moved inside them: a number below low becomes low, a number above high becomes high, and any other number stays as it is. The function that is tested, clamp_all, receives a vector nums and the limits and returns a vector with every number clamped, in the same order. The task asks you to do the comparing in the helper by hand, without a built-in min, max or clamp.

    For nums = [12, -3, 7, 25] with low = 0 and high = 20 the answer is [12, 0, 7, 20]. With negative limits, [-8, -1, 4] and limits -5 and 5 give [-5, -1, 4]. When both limits are 6, every number becomes 6. The limits are never in the wrong order: low is never greater than high.

    Approach

    Split the work. The helper knows how to handle one number; clamp_all knows how to visit every number. Once the helper is right, clamp_all is a plain loop that pushes the helper's answer for each number. Neither function has to think about the other's job, and each is easy to check on its own.

    Step by step

    1. In clamp, if x < low, return low.
    2. Then, if x > high, return high.
    3. Return x. Only a number between the limits gets here, so no else is needed.
    4. In clamp_all, create an empty mutable Vec named clamped. Rust works out its element type from what you push.
    5. Loop over &nums. Each num is a reference, so the loop doesn't take numbers out of the vector.
    6. Push Self::clamp(*num, low, high). The loop needs no if: the helper does all the comparing.
    7. Return clamped after the loop.

    The solution in Rust

    impl Solution {
        fn clamp(x: i32, low: i32, high: i32) -> i32 {
            if x < low {
                return low;
            }
            if x > high {
                return high;
            }
            return x;
        }
        fn clamp_all(nums: Vec<i32>, low: i32, high: i32) -> Vec<i32> {
            let mut clamped = Vec::new();
            for num in &nums {
                clamped.push(Self::clamp(*num, low, high));
            }
            return clamped;
        }
    }
    

    Rust details

    • Self::clamp. Both functions live in an impl block, so one calls the other as Self::clamp(...). A bare clamp(...) does not compile: the compiler reports cannot find function `clamp` in this scope and suggests Self::clamp.
    • *num. The loop gives references, but the helper takes an i32. Passing num as it is fails with mismatched types, and the compiler suggests dereferencing it.
    • Early returns. Each return ends the helper at once. After the first if returns, the second one only ever sees numbers that are not below low.

    Why split the work

    The helper is a tiny function with one job and a clear contract: one number and two limits in, one number out. That makes it easy to test alone. The three calls clamp(-3, 0, 20), clamp(25, 0, 20) and clamp(7, 0, 20) cover all three cases: below, above and inside. Once they behave, clamp_all can trust the helper and only has to repeat it.

    If the rule ever changes, only the helper changes. The loop in clamp_all would stay exactly as it is. This is the habit the lesson is practising: when a task has a small piece that repeats, give the piece its own function with a name that says what it does.

    The built-in you are not using

    Rust numbers have their own clamp method, so 7i32.clamp(0, 20) gives 7. The task asks you to write the comparisons yourself so you see what such a method does. A built-in clamp also panics when the lower limit is greater than the upper one; the lesson guarantees that never happens, and the helper above has no such case to worry about.

    The name clamp in your own impl block does not clash with the built-in: yours is called as Self::clamp(...), the built-in as a method on a number.

    Trying it

    clamp_all([12, -3, 7, 25], 0, 20)  ->  [12, 0, 7, 20]
    clamp_all([-8, -1, 4], -5, 5)      ->  [-5, -1, 4]
    clamp_all([3, 9, 6], 6, 6)         ->  [6, 6, 6]
    clamp(-3, 0, 20), clamp(25, 0, 20), clamp(7, 0, 20)  ->  0, 20, 7
    

    Edge cases

    Numbers that sit exactly on a limit stay where they are, and numbers far outside move to the nearest limit. For [0, 20, 1000, -1000] with limits 0 and 20 the result is [0, 20, 20, 0]: 0 and 20 are already inside, 1000 drops to 20 and -1000 rises to 0. A vector with one number works like any other, and wide limits leave it alone: [5] with limits -1000 and 1000 stays [5].

    The vector is never empty in this lesson. If it were, the loop would simply not run and the function would return an empty vector.

    Common mistakes

    • Swapping the limits' roles. Returning high for a number below low flips the result. Read each if aloud: "below the lower limit, return the lower limit".
    • Using <= or >=. That is harmless for the result (a number equal to low becomes low anyway), but it adds a case that is not needed.
    • Changing the order. Push in the loop's order and the result matches the input position by position.
    • Doing the comparing in clamp_all. The loop should only call the helper; that is the point of the split.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free