Skip to content

Instantly share code, notes, and snippets.

@snth
Last active December 18, 2024 14:43
Show Gist options
  • Save snth/bf73dcfee83ea10af33200a8bd8112af to your computer and use it in GitHub Desktop.
Save snth/bf73dcfee83ea10af33200a8bd8112af to your computer and use it in GitHub Desktop.
This gist implements the TRIMRANGE function as a LAMBDA in Excel Labs
/*
TRIMRANGE (https://support.microsoft.com/en-us/office/trimrange-function-d7812248-3bc5-4c6b-901c-1afa9564f999)
Excludes empty rows and/or columns from the outer edges of a range or array
by scanning inward until finding non-blank cells.
Inputs:
- range: The range or array to be trimmed
- trim_rows (optional, default=3): Controls row trimming
0 = Keep all rows
1 = Remove leading blank rows
2 = Remove trailing blank rows
3 = Remove both leading and trailing blank rows
- trim_cols (optional, default=3): Controls column trimming
0 = Keep all columns
1 = Remove leading blank columns
2 = Remove trailing blank columns
3 = Remove both leading and trailing blank columns
Return:
The input range with specified blank rows/columns removed from the edges.
Note:
This function can also be called using trim references for shorter syntax:
A1.:.E10 = TRIMRANGE(A1:E10,3,3) - Trim both edges
A1:.E10 = TRIMRANGE(A1:E10,2,2) - Trim trailing edges
A1.:E10 = TRIMRANGE(A1:E10,1,1) - Trim leading edges
*/
TRIMRANGE = LAMBDA(range, [trim_rows], [trim_cols],
LET(
_trim_rows, IF(ISOMITTED(trim_rows), 3, trim_rows),
_trim_cols, IF(ISOMITTED(trim_cols), 3, trim_cols),
_double, LAMBDA(n, n * 2),
_select_rows, LAMBDA(_range, _start, _end, direction,
DROP(TAKE(_range, direction * _end, ), direction * (_start - 1), )
),
_select_cols, LAMBDA(_range, _start, _end, direction,
DROP(TAKE(_range, , direction * _end), , direction * (_start - 1))
),
_check_empty, LAMBDA(_range, _rangefunc, _width, _direction,
LAMBDA(_lb,
LET(
_checkrange, _rangefunc(_range, _lb, _double(_lb) - 1, _direction),
AND(0 = COUNTA(_checkrange), _lb <= _width)
)
)
),
_trim, LAMBDA(rangefunc, start, end, direction,
LET(
_loop, LAMBDA(state, predicate, update,
LET(
_loop, LAMBDA(_state, _self,
IF(predicate(_state), _self(update(_state), _self), _state)
),
_loop(state, _loop)
)
),
_trim_recursive, LAMBDA(_rangefunc, _start, _end, self,
LET(
_lb, _loop(
1,
_check_empty(
_rangefunc(range, _start, _end, direction),
_rangefunc,
_end - _start + 1,
direction
),
_double
),
_result, IF(
_lb = 1,
_start,
self(
_rangefunc,
(_start - 1) + _lb,
(_start - 1) + _double(_lb) - 1,
self
)
),
_result
)
),
_trim_recursive(rangefunc, start, end, _trim_recursive)
)
),
_firstrow, IF(BITAND(_trim_rows, 1), _trim(_select_rows, 1, ROWS(range), 1), 1),
_firstcol, IF(BITAND(_trim_cols, 1), _trim(_select_cols, 1, COLUMNS(range), 1), 1),
_lastrow, IF(
BITAND(_trim_rows, 2),
ROWS(range) + 1 - _trim(_select_rows, 1, ROWS(range), -1),
ROWS(range)
),
_lastcol, IF(
BITAND(_trim_cols, 2),
COLUMNS(range) + 1 - _trim(_select_cols, 1, COLUMNS(range), -1),
COLUMNS(range)
),
_trimrange, DROP(TAKE(range, _lastrow, _lastcol), _firstrow - 1, _firstcol - 1),
_trimrange
)
);
@matthews-p
Copy link

Brilliant! Dumb question: was there a reason you gave the default enumerations a value of 3, rather than zero? I realize it's an arbitrary/aesthetic thing, it just seems more intuitive to me 😄

@snth
Copy link
Author

snth commented Dec 18, 2024

Hi @matthews-p ,

Sorry, I didn't notice your comment until now.

I just copied the official API and that's how they specified it: https://support.microsoft.com/en-us/office/trimrange-function-d7812248-3bc5-4c6b-901c-1afa9564f999

image

@matthews-p
Copy link

Got it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment