MENU
Donate
=EBOOK

LAMBDA & Dynamic Arrays

Unlock modern Excel: write reusable custom functions with LAMBDA, LET, and the dynamic array functions that replace complex old formulas.

advanced~26 pagesJuly 31, 2026

Downloading requires a free Google sign-in -- why?

Or get it by email

=CONTENTS

What's inside

Excel changed fundamentally in 2019 when Microsoft introduced dynamic arrays. Before that, getting a formula to return multiple values required pressing Ctrl+Shift+Enter and hoping the result landed in exactly the right number of cells. Today, a single formula can spill an entire filtered, sorted, deduplicated table into a worksheet with no special handling required. If you have been building complex nested IF statements and multi-step VLOOKUP chains, this ebook will show you a cleaner way to work.

This guide is for Excel users who already know their way around common lookup and reference functions. You should be comfortable with XLOOKUP or VLOOKUP, understand how relative and absolute cell references work, and have used at least a few IF-based formulas. What you may not have explored yet is the dynamic array engine — FILTER, SORT, UNIQUE, SEQUENCE — and the two functions that sit above all of them: LET, which lets you name intermediate calculations inside a formula, and LAMBDA, which lets you define entirely new functions that live in your workbook.

Work through the chapters in order the first time. The later sections on LAMBDA, MAP, and REDUCE build directly on the dynamic array concepts introduced earlier, and the real-world use cases in Chapter 10 pull every technique together into patterns you can copy straight into your own files. All formulas in this ebook assume Excel 365 or Excel 2021. If a function does not appear on your version, check whether your organisation’s Microsoft 365 channel is set to Current Channel, which receives new features first.

The Dynamic Array Revolution

Dynamic arrays are not just new functions — they represent a new calculation model. Any formula that returns more than one value now automatically spills those values into adjacent cells, expanding as far as necessary. This single change makes an enormous number of previously awkward formulas straightforward.

The Spill Range and the # Operator

When a dynamic array formula runs, Excel places the top-left result in the formula cell and fills the remaining values into the cells below or to the right. That occupied region is called the spill range. If anything blocks the spill — another value, a merged cell, even a space character — Excel shows a #SPILL! error until the obstruction is cleared.

The hash operator (#) lets you reference an entire spill range by pointing at just the formula cell. Suppose a UNIQUE formula in D2 spills ten distinct values into D2:D11. Any other formula can reference the whole list as D2# rather than D2:D11, and if the list grows or shrinks, D2# updates automatically.

=UNIQUE(B2:B50)
(dynamic array)

The formula above spills every distinct value from column B into consecutive cells. Anywhere else in the sheet, reference the result with:

=COUNTA(D2#)
10

That count adjusts the moment the source data changes — no manual range adjustment needed.

Legacy Ctrl+Shift+Enter Arrays

Before dynamic arrays, power users pressed Ctrl+Shift+Enter to create what are sometimes called CSE arrays or legacy arrays. You will still encounter these in older workbooks, wrapped in curly braces: {=SUM(IF(B2:B20>100,C2:C20,0))}. Dynamic arrays make most CSE arrays unnecessary, and mixing the two styles in one formula is rarely worthwhile. When you find a CSE array that a dynamic function can replace, rewrite it — the modern version will be easier to maintain and will not confuse colleagues who have never seen curly-brace formulas.

FILTER — Extracting Conditional Subsets

FILTER is the function that replaces the most common reason people used to reach for Advanced Filter or a macro. It returns every row from a range that meets one or more criteria, and the result updates automatically when the source data changes.

Basic Syntax

=FILTER(array, include, [if_empty])
  • array — the range of data you want to return (can be multiple columns)
  • include — a TRUE/FALSE array the same height as array; rows where this is TRUE are returned
  • if_empty — optional; what to show if nothing matches (without this, FILTER returns #CALC! when no rows pass)
=FILTER(A2:C20,B2:B20>100,"No results")
(dynamic array)

That formula returns every row from A2:C20 where column B exceeds 100. Add the third argument so the cell does not sit blank when the filter finds nothing.

Multiple Conditions

Combine conditions with multiplication for AND logic and addition for OR logic. Multiplication works because TRUE is 1 and FALSE is 0 — multiplying two TRUE/FALSE arrays gives 1 only when both are TRUE.

=FILTER(A2:C20,(B2:B20>100)*(C2:C20="East"))
(dynamic array)

For OR logic, use addition and wrap in a double negative or comparison to convert to TRUE/FALSE:

=FILTER(A2:C20,(B2:B20>100)+(C2:C20="East"))
(dynamic array)

Any row where either condition is true has a sum of at least 1, which FILTER treats as TRUE.

A Rep, Revenue, Region table filtered with FILTER and a multiplied AND condition, spilling only the two East-region rows with revenue above 100.
Two TRUE/FALSE arrays multiplied together act as AND logic - only rows passing both survive.

FILTER with a Partial Match

ISNUMBER combined with SEARCH gives you a contains-style text filter:

=FILTER(A2:C20,ISNUMBER(SEARCH("north",A2:A20)),"No match")
(dynamic array)

SEARCH is case-insensitive; swap it for FIND if case matters.

SORT and SORTBY — Ordered Results on the Fly

Sorting a range used to mean selecting it, running Data > Sort, and repeating whenever the data changed. SORT and SORTBY return a sorted copy of a range as a formula result, leaving the source unchanged.

SORT

=SORT(array, [sort_index], [sort_order], [by_col])
  • sort_index — which column (or row) to sort by; defaults to 1
  • sort_order — 1 for ascending (default), -1 for descending
  • by_col — FALSE to sort rows (default), TRUE to sort columns
=SORT(A2:C20,2,-1)
(dynamic array)

This returns A2:C20 sorted by the second column, largest to smallest.

SORTBY

SORTBY is more flexible: the column you sort by does not have to be in the returned array, and you can chain multiple sort levels.

=SORTBY(array, by_array1, [sort_order1], [by_array2], [sort_order2], ...)
=SORTBY(A2:A20,B2:B20,-1,C2:C20,1)
(dynamic array)

That returns column A, sorted first by column B descending, then by column C ascending — a two-level sort in a single formula.

Sorting a FILTER Result

Because dynamic array functions return arrays, they chain naturally:

=SORT(FILTER(A2:C20,C2:C20="West"),2,-1)
(dynamic array)

One formula: filter to the West region, sort the result by the second column descending. No helper columns, no intermediate tables.

UNIQUE — Deduplicating Lists Automatically

UNIQUE extracts distinct values from a list or range, updating automatically as the source changes. It is the formula equivalent of Data > Remove Duplicates, but non-destructive — the source data stays intact.

Basic Syntax

=UNIQUE(array, [by_col], [exactly_once])
  • by_col — FALSE returns unique rows (default), TRUE returns unique columns
  • exactly_once — FALSE returns each distinct value once (default), TRUE returns only values that appear exactly once
=UNIQUE(B2:B50)
(dynamic array)
=UNIQUE(A2:C50)
(dynamic array)

The second example returns unique rows across all three columns — a row is only included if no other row has the same combination in columns A, B, and C.

UNIQUE + SORT for Clean Drop-Down Lists

Combining UNIQUE and SORT is the standard recipe for a self-updating source list for data validation drop-downs, covered in detail in Chapter 10.

=SORT(UNIQUE(B2:B100))
(dynamic array)
A Region column with repeated values next to a Sorted Unique List spilling East, North, West alphabetically, and a Distinct Count of 3.
SORT(UNIQUE(…)) - the standard recipe for a self-updating drop-down source list.

Counting Distinct Items

Wrap UNIQUE in COUNTA to count how many distinct values exist:

=COUNTA(UNIQUE(B2:B100))
14

SEQUENCE — Generating Number and Date Series

SEQUENCE fills a range with a series of numbers, which you can shape into rows, columns, or grids and shift by any start value and step.

Basic Syntax

=SEQUENCE(rows, [cols], [start], [step])
Argument Default Meaning
rows required number of rows in the output
cols 1 number of columns
start 1 first value
step 1 increment between values
=SEQUENCE(10)
(dynamic array)

Returns 1, 2, 3 … 10 in a single column.

=SEQUENCE(5,4,0,5)
(dynamic array)

Returns a 5-row by 4-column grid starting at 0, incrementing by 5: 0, 5, 10, 15 across the first row, 20, 25, 30, 35 across the second, and so on.

Date Series with SEQUENCE

Because Excel dates are serial numbers, SEQUENCE generates date ranges directly:

=SEQUENCE(12,1,DATE(2026,1,1),30)
(dynamic array)

That produces twelve dates spaced thirty days apart starting 1 January 2026 — a quick way to build a monthly schedule header.

For the first day of each month specifically, wrap with EOMONTH:

=EOMONTH(DATE(2026,1,1),SEQUENCE(12,1,0,1)-1)+1
(dynamic array)

Row Numbers for Formulas

SEQUENCE(ROWS(A2:A100)) generates a helper column of row offsets without occupying a real column, useful inside INDEX-based constructions where you previously would have dragged down a 1, 2, 3 series.

Combining Dynamic Array Functions

The real power comes from nesting these functions. Each returns an array, so the output of one is a valid input to another.

Ranked Unique List

Extract distinct values and rank them by a related metric in one step:

=SORTBY(UNIQUE(B2:B100),COUNTIF(B2:B100,UNIQUE(B2:B100)),-1)
(dynamic array)

UNIQUE pulls the distinct items; COUNTIF counts how many times each appears in the original range; SORTBY arranges the unique list by those counts, highest first. The result is a frequency-ranked list with no pivot table required.

Filtered and Sorted Multi-Column Output

=SORT(FILTER(A2:D200,(C2:C200="Closed")*(D2:D200>10000)),4,-1)
(dynamic array)

Returns all closed deals worth more than 10 000, sorted by the value column (column 4) from largest to smallest.

SEQUENCE Inside INDEX

A common pattern before dynamic arrays was to drag INDEX down a column to pick different rows. SEQUENCE replaces the drag:

=INDEX(A2:A100,SEQUENCE(5,1,MATCH(MAX(B2:B100),B2:B100,0)))
(dynamic array)

That starts from the row of the maximum value and returns five consecutive names — useful for extracting a top-N block when you already know the position.

LET — Naming Formula Steps for Clarity

LET solves a problem every formula writer eventually hits: you need the same sub-calculation in three places inside one formula, so you either repeat it three times (making the formula fragile) or introduce a helper cell (breaking the single-formula approach). LET gives you named variables inside a formula.

Basic Syntax

=LET(name1, value1, [name2, value2, ...], calculation)

You define pairs of name and value, then the final argument is the expression that uses those names.

=LET(sales,B2:B100,target,C2:C100,FILTER(sales,sales>target))
(dynamic array)

Here sales and target are calculated once and reused in the FILTER. With long ranges or complex sub-expressions, this makes formulas dramatically easier to read and modify.

A Practical LET Example

Without LET, a bonus calculation that references the same adjusted-salary expression three times looks like this:

=IF((B2*1.08)>50000, (B2*1.08)*0.15, IF((B2*1.08)>30000, (B2*1.08)*0.10, (B2*1.08)*0.05))

With LET:

=LET(adj,B2*1.08,IF(adj>50000,adj*0.15,IF(adj>30000,adj*0.10,adj*0.05)))
(dynamic array)

The adjusted salary is computed once. If the 1.08 multiplier changes, you update it in one place.

A Base Salary of $42,000 next to a Bonus formula using LET to name the adjusted-salary expression once and reuse it inside a nested IF, returning $4,536.00.
LET names the repeated sub-expression once instead of writing it three times.

LET with Dynamic Arrays

LET works naturally with array-returning functions. Naming an intermediate filtered result and then sorting it reads much more clearly than nesting SORT directly inside FILTER:

=LET(filtered,FILTER(A2:C100,B2:B100="West"),SORT(filtered,3,-1))
(dynamic array)

Name the filtered set, then sort it. Each step is readable on its own.

LAMBDA — Writing Your Own Excel Functions

LAMBDA is the most significant addition to the Excel formula language in decades. It lets you define a reusable custom function — with named parameters — entirely inside a formula. Once saved to Name Manager, your LAMBDA function works exactly like a built-in function across the entire workbook.

Basic Syntax

=LAMBDA(param1, [param2, ...], calculation)

Typed directly in a cell, a LAMBDA does nothing until you call it by appending parentheses with arguments:

=LAMBDA(x, x^2)(5)
25

That calls an anonymous squaring function with 5 as the argument. Anonymous LAMBDA calls are useful for testing, but the real value comes from storing them in Name Manager.

Creating a Named LAMBDA Function

  1. Open Formulas tab > Name Manager > New.
  2. Give the name something descriptive, such as TAXRATE.
  3. In the Refers To box, enter the LAMBDA formula — no leading = is required by some versions, but include it to be safe:
=LAMBDA(income, IF(income>100000, 0.37, IF(income>44725, 0.22, 0.12)))
  1. Click OK.

Now anywhere in the workbook you can write:

=TAXRATE(B2)
0.22

Change the brackets in Name Manager once and every cell using TAXRATE updates.

An Income column with a Tax Rate column calling TAXRATE(A3), a custom LAMBDA function saved in Name Manager, returning 12%, 22%, and 37% for three income levels.
TAXRATE works exactly like a built-in function - it’s just a LAMBDA saved once in Name Manager.

Recursive LAMBDA

LAMBDA supports recursion via a second optional name argument. The pattern is to give the LAMBDA its own name as a parameter so it can call itself:

=LAMBDA(FACTORIAL, n, IF(n<=1, 1, n * FACTORIAL(FACTORIAL, n-1)))

Store this as FACTORIAL in Name Manager, then call it:

=FACTORIAL(FACTORIAL,6)
720

Recursive LAMBDA is advanced territory — most workbook problems do not need it — but it removes the last category of things that genuinely required VBA for formula-only work.

LAMBDA Best Practices

Keep each LAMBDA focused on one transformation. If a function needs ten parameters, it is almost always clearer to break it into two or three named LAMBDAs that call each other. Document the parameter names carefully in the Name Manager Comment field — your future self will thank you when the workbook reappears six months later.

MAP, REDUCE, BYROW, BYCOL

These four functions apply a LAMBDA to every element of an array, or accumulate an array down to a single value. They arrive as a group and are designed to be used with LAMBDA.

MAP

MAP applies a LAMBDA to every element of one or more arrays and returns an array of the same shape.

=MAP(array1, [array2, ...], lambda)
=MAP(A2:A20,LAMBDA(x,x*1.1))
(dynamic array)

Returns every value in A2:A20 increased by ten percent. This is equivalent to =A2:A20*1.1 for simple arithmetic, but MAP becomes valuable when the per-element logic involves a named LAMBDA that encapsulates complexity.

With two arrays, MAP passes one element from each to the LAMBDA simultaneously:

=MAP(B2:B20,C2:C20,LAMBDA(price,qty,price*qty))
(dynamic array)

Element-wise multiplication of two columns — similar to =B2:B20*C2:C20 but named and explicit.

REDUCE

REDUCE accumulates an array into a single value by applying a LAMBDA repeatedly. The LAMBDA receives the running accumulator and the current element.

=REDUCE([initial_value], array, lambda)
=REDUCE(0,B2:B20,LAMBDA(acc,x,acc+x))
1450

This is equivalent to SUM, but REDUCE handles accumulations that no built-in function covers directly. For example, a running product:

=REDUCE(1,B2:B10,LAMBDA(acc,x,acc*x))
(dynamic array)

BYROW and BYCOL

BYROW and BYCOL apply a LAMBDA to each row or each column of a range and return an array of one result per row or column.

=BYROW(array, lambda)
=BYCOL(array, lambda)
=BYROW(B2:E20,LAMBDA(row,MAX(row)))
(dynamic array)

Returns the maximum value in each row across four columns — a 19-value column of row maxima. Previously this required either MAX with IF as a CSE array or a helper column.

=BYCOL(B2:E20,LAMBDA(col,AVERAGE(col)))
(dynamic array)

Returns four values — the average of each column. A column of averages without a SUBTOTAL or a separate AVERAGE row.

Combining MAP and LAMBDA

The real benefit of MAP is pairing it with a named LAMBDA. If TAXRATE is already defined in Name Manager:

=MAP(B2:B100,LAMBDA(income,TAXRATE(income)))
(dynamic array)

Apply your custom function to every row in one formula. When the tax logic changes, update TAXRATE once.

Real-World Use Cases

Dynamic Dependent Drop-Downs

Standard data validation drop-downs require a fixed range. With UNIQUE and SORT producing a spill range, you can point a drop-down at D2# and it will always contain the current distinct values from your source column.

Step 1: In D2, build the master unique list:

=SORT(UNIQUE(B2:B500))
(dynamic array)

Step 2: In a second helper column, say F2, build a filtered list for a dependent drop-down. If the first drop-down selection lands in H1:

=SORT(UNIQUE(FILTER(C2:C500,B2:B500=H1)))
(dynamic array)

Step 3: Select the cells where the dependent drop-down should appear. Go to Data tab > Data Validation > Allow: List. In the Source box, type =$F$2#. Excel accepts the spill reference and the list grows or shrinks as H1 changes.

This technique replaces the traditional approach of building a named range for every possible parent value — a maintenance nightmare on large datasets.

Auto-Ranked Leaderboard

A leaderboard that stays correct without sorting the source data and without a pivot table:

Source data: Names in column A, scores in column B, region in column C.

Leaderboard formula (paste into E2):

=SORTBY(FILTER(A2:C100,C2:C100="North"),FILTER(B2:B100,C2:C100="North"),-1)
(dynamic array)

That returns the North region rows sorted by score, descending. Wrap the whole thing in TAKE to limit to top five:

=TAKE(SORTBY(FILTER(A2:C100,C2:C100="North"),FILTER(B2:B100,C2:C100="North"),-1),5)
(dynamic array)

TAKE(array, rows) returns the first N rows — available in Excel 365 from late 2022 onward. If TAKE is not available on your version, wrap the SORTBY in INDEX with SEQUENCE(5) to achieve the same top-five result:

=INDEX(SORTBY(FILTER(A2:C100,C2:C100="North"),FILTER(B2:B100,C2:C100="North"),-1),SEQUENCE(5),{1,2,3})
(dynamic array)

Building a Reusable AVERAGEIF-Style LAMBDA

Excel has AVERAGEIF, but no AVERAGEIFS-equivalent that handles arrays gracefully. A LAMBDA covers the gap:

In Name Manager, define AVGIF as:

=LAMBDA(range, criteria_range, criteria,
    AVERAGE(IF(criteria_range=criteria, range)))

Call it:

=AVGIF(D2:D100,C2:C100,"West")
4820

Any time the filter logic becomes more complex — say, criteria drawn from a spill range — the LAMBDA body handles it and every call site stays clean.

Month-Over-Month Summary with SEQUENCE and SUMIFS

Generate a summary table of monthly totals without a pivot table:

In G2, place the month start dates:

=EOMONTH(DATE(2026,1,1),SEQUENCE(12,1,0,1)-1)+1
(dynamic array)

In H2, reference the spill range to sum each month:

=SUMIFS(C2:C500,B2:B500,">="&G2#,B2:B500,"<"&EOMONTH(G2#,0)+1)
(dynamic array)

One formula in H2 produces twelve monthly totals aligned with the dates in G2. Add new transactions to columns B and C and both columns update instantly.

Where to Go Next

The functions in this ebook form the productive core of modern Excel formula writing, but they connect to broader skills. The resources below will help you apply what you have learned:

  • Excel Formulas Cheat Sheet — a quick-reference companion covering the essential functions LAMBDA and dynamic arrays rely on, including TEXT, DATE, and logical functions
  • Excel Intermediate Skills — if any section in this ebook felt like a stretch, that guide fills the gaps with named ranges, data validation, and structured table references
  • Microsoft’s official Excel function reference — the authoritative syntax reference for every function covered here, including argument constraints and version availability notes
  • The Name Manager (Formulas tab > Name Manager) — your LAMBDA library lives here; take time to document each entry with a comment explaining parameters and purpose before sharing the workbook
  • Excel’s Trace Dependents and Evaluate Formula tools (Formulas tab > Formula Auditing) — essential for debugging nested dynamic array formulas when a result looks wrong; Evaluate Formula steps through the calculation in sequence, showing the intermediate array at each stage

Want a bigger dataset to practice FILTER, SORT, and UNIQUE on? Download the SUMIFS / COUNTIFS practice dataset - 200 rows across region, product, month, and salesperson, plenty of real structure for multi-condition FILTER formulas and ranked UNIQUE lists.

That's the whole book. Keep the PDF for offline reading.

Download PDF

Get the PDF by email instead