Cap each value to a [lo, hi] range. Values below lo become lo, values above hi become hi, and values already in range are unchanged. By hand, apply a three-way branch in a loop. With pandas, Series.clip(lo, hi) performs the same capping in one call.

By hand

For each value, check if v < lo → append lo, elif v > hi → append hi, else → append v unchanged. The trace shows all three branches in action: under-range inputs (3 and 2) hit the first branch, over-range inputs (42 and 28) hit the second, and in-range inputs fall through to else.

naive.py
values = [3, 15, 7, 42, 11, 2, 28, 9]
lo = 5
hi = 25
result = []
for v in values:
    if v < lo:
        result.append(lo)
    elif v > hi:
        result.append(hi)
    else:
        result.append(v)
print('RESULT:', result)

With pandas

Series.clip(lo, hi) caps every element to the given bounds in one pass. The snapshot shows values before and after so the replacements are immediately visible.

library.py
import pandas as pd
from dalib.display import set_display
set_display()

values = [3, 15, 7, 42, 11, 2, 28, 9]
lo = 5
hi = 25
df = pd.DataFrame({'x': values})
clipped = df['x'].clip(lo, hi)
result = clipped.tolist()
print('index:', clipped.index.tolist())
print('dtype:', clipped.dtype)
print('values before:', df['x'].tolist())
print('values after:', clipped.tolist())
print('RESULT:', result)
index: [0, 1, 2, 3, 4, 5, 6, 7]
dtype: int64
values before: [3, 15, 7, 42, 11, 2, 28, 9]
values after: [5, 15, 7, 25, 11, 5, 25, 9]
RESULT: [5, 15, 7, 25, 11, 5, 25, 9]

Implementation notes

  • clip preserves the dtype when all values and bounds are the same numeric type; integer input with integer bounds returns int64.
  • Clipping to a fixed range is sometimes called Winsorizing — replacing extremes with boundary values rather than discarding them.
  • Pass only one bound to clip on one side: s.clip(lower=lo) or s.clip(upper=hi).
  • Cross-reference: where-replace (numpy chapter) for conditional replacement using np.where.