End User Friendly Solution

Should our approach change when a non technical person has to maintain the solution moving forward.

Read more: End User Friendly Solution

Excel BI Challenge

Here’s another Excel challenge from Excel (Vijay A. Verma) BI that I’ll use as an example.

Given the data at the top of the image, create the summary below that lists Name and Year for all maximum and minimum values.

Solutions

Of the dozens of amazing solutions in the LinkedIn post, here are two:

Single Formula

Efficient single step formula from Meganathan Elumalai:

=LET(l,LAMBDA(f,c,IFNA(HSTACK(c,TEXTSPLIT(CONCAT(TOCOL(IFS(f(F105:M109)=F105:M109,E105:E109&"|"&F104:M104),3)&","),"|",",",1)),"")),VSTACK(l(MAX,"Max"),l(MIN,"Min")))

Power Query

Clear and concise M code from Kris Jaganah:

let
 
 A = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
 B = Table.UnpivotOtherColumns(A, {"Name"}, "Year", "Z"),
 C = (w)=> [a = Table.SelectRows(B, each [Z] =  w(B[Z]) ),
 b = Table.AddColumn(a, "Category",(v)=> let 
 p = if List.Max( B[Z]) = a{0}[Z] then "Max" else "Min" 
 in if a{0}[Name] = v[Name] then p else null)[[Category],[Name],[Year]]][b]
in
 C(List.Max)& C(List.Min)

There are many other amazing solutions in Excel BI’s LinkedIn post.

What’s the Problem?

These solutions work perfectly. If changes are needed, the end user should reach out to the author, right?

The solution creator might be long gone or super busy with another project by the time a minor change is required. Non data professionals would likely struggle to update either solution.

What should we do?

A Question

The data we’ve been given looks similar to Pivot Table data. Meganathan and Kris (and others) created solutions built directly on the data provided:

Should we ask if there is source data behind this and use that to build a solution that’s potentially less complex?

Alternative Solutions

If the raw unaggregated data is already in the same Excel file then we might consider building the solution on that instead. The data might look something like this:

Power Query solution

I loaded this data to Power Query and created a series of 7 very basic queries:

Anyone of us could audit and explain these steps to a non technical person. It’s not fancy and it hurts to see something so basic but sometimes this is easier on the end user.

Also possible is a single query (Table3_all_inPQ) that uses the Given Data:

Here’s the M code for above solution:

let
    //LOAD THE EXCEL DATA INTO P.Q.
    Source = Excel.CurrentWorkbook(){[Name="Table3"]}[Content],
    
    //REARRANGE THE DATA
    #"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"Name"}, "Attribute", "Value"),
    
    //RENAME COLUMN HEADERS
    #"Renamed Columns" = Table.RenameColumns(#"Unpivoted Other Columns",{{"Attribute", "Year"},{"Value","Data"}}),

    //GET THE MINIMUM VALUE
    #"Grouped RowsMIN" = Table.Group(#"Renamed Columns", {}, {{"MIN", each List.Min([Data]), type number}}),
    MINval = #"Grouped RowsMIN"{0}[MIN],

    //GET THE MAXIMUM VALUE
    #"Grouped RowsMAX" = Table.Group(#"Renamed Columns", {}, {{"MAX", each List.Max([Data]), type number}}),
    MAXval = #"Grouped RowsMAX"{0}[MAX],

    //FILTER TO ROWS THAT HAVE EITHER A MIN OR MAX VALUE
    #"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each [Data] = MINval or [Data] = MAXval ),

    //SORT DATA BY MAX VALUES FOLLOWED BY MIN VALUES
    #"Sorted Rows" = Table.Sort(#"Filtered Rows",{{"Data", Order.Descending},{"Name", Order.Ascending},{"Year", Order.Ascending}}),
    
    //CREATED A COLUMN TO DISPLAY CATEGORY (MAX AND MIN)
    #"Added Custom" = Table.AddColumn(#"Sorted Rows", "Category", each if [Data] = MINval then "Min" else "Max"),
    
    //REORDER THE COLUMNS AND REMOVE COLUMNS WE DON'T NEED
    #"Reordered Columns" = Table.ReorderColumns(#"Added Custom",{"Category", "Name", "Year", "Data"}),
    #"Removed Columns" = Table.RemoveColumns(#"Reordered Columns",{"Data"})
    
in
    #"Removed Columns"

MUCH longer code but my M code knowledge is not at the level of Kris Jaganah, Bill Szysz, Melissa de Korte and others.

Formula solution

If we have the raw unaggregated data we could use this formula to aggregate it:

=PIVOTBY(Table1[[#All],[Name]:[Year]],,Table1[[#All],[Data]],SUM,3,0)

The aggregated data is now in a friendlier layout:

Two simple formulas calculate MAX value (cell AL120) and MIN value (cell AL121), and then this formula:

=VSTACK(
FILTER(AJ3:AL42,AL3:AL42=AL120),
FILTER(AJ3:AL42,AL3:AL42=AL121))

Finally, a simple formula to display MAX and MIN only once each:

=IF(AM126=$AL$120,"Max",IF(AM126=$AL$121,"Min",""))

Boring but so much easier to explain to someone else (and minimize follow up questions!).

About Me

My name is Kevin Lehrbass. I’m a data analyst. I can *think* in Excel formulas easily. I’m training my brain more and more to *think* in M code and DAX…while also reviewing SQL and VBA!

There are so many amazing Excel challenges in LinkedIn. I can’t keep up! My favorites are from:

Learn Power Query M code

If you’re intimated by M code, this post is for you. I’ll explain techniques I use for understanding M code.

Read more: Learn Power Query M code

M code?

Power Query is a Microsoft ETL tool used in Excel and Power BI. M code is generated when we interact with the user interface to change our data.

Challenge

We need a good problem to learn from. This fun challenge is from an Excel BI Analytics LinkedIn post. Thank you Vijay A. Verma!

Requirement

Given the data on the left, rearrange and calculate it to end up with data on the right. Each person has a start Date & Time to be subtracted from their end Date & Time to provide a time duration.

This is a sample. Imagine a real data-set with 200000 rows! Here’s the Power Query M code from Kris Jaganah that we WILL understand soon!

let
 A = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
 B = Table.ToColumns(A),
 C = List.Select( B{0}, each Text.From(_)=_),
 D = List.Transform( List.Difference( B{0}, C ),Number.From),
 E = List.Transform( List.Split( List.Transform({0..List.Count(D)-1}, each D{_} +List.RemoveNulls( B{1}){_}),2) , (x)=> (x{1}-x{0})*24),
 F = Table.FromColumns( {C,E},{"Name","Duration"})
in
 F

Why is all this M code necessary? We have bad data. Name & Date has two different data items. That shouldn’t happen! We have three items:

  • Name
  • Start Date Time
  • End Date Time.

Each should be a separate column. But Power Query & M can solve this.

Techniques to Understand M Code

When auditing a Power Query solution I do this:

  • examine raw data and think about required steps
    • what needs to be done?
    • what’s the most challenging part?
  • open Power Query, study applied steps one by one, back and forth
    • it REALLY helps to see how the data changes in every step
  • open Advanced Editor to study M code
    • compare applied steps to M code (steps are converted into M code)
    • hover over M functions to see syntax (visit documentation)
    • some steps are simple, others combine functions (write it out on paper)
    • break long steps into new queries to see data created

I assumed Kris would rearrange data to a row per person with three columns: Name, Start Date Time, End Date Time. I was wrong and learned a lot!

Examine Raw Data

There’s a million ways to solve this but all solutions will have to:

  • extract text names from Name & Date
  • add Time to Date for each row
  • per person calculate Start Date Time & End Date Time difference
  • horizontally align Name and Duration (columns D & E)

Applied Steps

Open Power Query

We don’t have to load data as we are auditing an existing solution.

  • on the ribbon select Data
  • on the left select Get Data
  • select Launch Power Query Editor

Study Applied Steps

  • data preview: what the data looks like after each step
  • applied steps: examine each step to see how the data has changed
  • formula bar: formula syntax generated by each applied step

We’ll start at the beginning with step A!

Step A

Under APPLIED STEPS, click A. Formula bar shows us this code:

= Excel.CurrentWorkbook(){[Name="Table1"]}[Content]

Kris loaded Table1, which we saw in sheet1, into Power Query:

  • active cell is anywhere within Table1 (cell A8 below)
  • select Data on the ribbon
  • select icon From Table/Range (section Get & Transform Data)

If you’re recreating this solution from the beginning please note:

  • by default, importing a table creates step Source. Kris renamed it to A.
  • he removed auto step Changed Type (P.Q. trying to help us…not needed here)

Excel.CurrentWorkbook imports data from the current Excel file. It belongs to a category of functions that connect to and import data.

Now, we’ll look behind the curtain at the M code! On the ribbon select Home and Advanced Editor:

Step A has a slightly different syntax than in the formula bar. Note:

  • keyword let is before all steps
  • step name (A) is listed followed by = and the formula bar code
  • each step, except the last one, ends with a comma
  • keyword in is after all steps (unless there’s a nested let & in!)
  • our final data (answer), typically the last step (F), is after in

In the bottom right corner select Close.

Now, prepare yourself for a wild ride into the magical realms of M code!

Step B

In step B, don’t think about WHY (that’s answered in a future step). Focus on WHAT’s happening for now.

Under APPLIED STEPS, click B. Formula bar shows us this code:

B = Table.ToColumns(A),

Function Table.ToColumns references step A. Table.ToColumns syntax is:

Table.ToColumns(table as table) as list

To understand step B, we need to review Structured Types. Think of them as things: planes, trains, and cars that share a common purpose (take you somewhere) but are all unique.

Structured Types: collections of things or values:

table most common Power Query object type (step A is a table). A collection of data organized in rows and columns (like a database)

list ordered sequence of values. Lists have a single column. Step B uses list function Table.ToColumns to convert Step A columns into a list

record named fields, like a row in a table. Records represent individual data entries

Each type has it’s own functions that perform actions.

Below, in step B, note the following:

  • list function Table.ToColumns references step A table and creates a list
  • it’s a list with nested lists! Step A’s table columns have become lists in step B!
  • I selected the first nested list to peer inside: all step A column Name & Date values are inside

We’ll get to the WHY, but at least we understand WHAT happened in step B. Feel free to glance at the M code in the Advanced Editor again.

Step C

Step C output is below. All four names are extracted! Now we understand step B’s purpose. Step C uses list function List.Select to extract text items from the first nested list in step B.

We now know WHAT step C did but HOW did it do it? The formula bar displays this code:

= List.Select( B{0}, each Text.From(_)=_)

Remember: function syntax helps us unravel the mystery:

List.Select(list as list, selection as function) as list

list as list List.Select asks for a list. B{0} gives it the first embedded list from step B (M code is zero based meaning counting starts with 0 not 1).

each Text.From(_)=_) function Text.From converts each list item into a text. For each item, convert it to a text and compare =_ it to the original list value. If they’re both text then keep them! So, only original text values will be the same as values converted to text.

I played with the syntax and removed the comparison part at the end =_ Without this, all values become text and remain. A tricky piece of syntax!

It gives us a four item list of names (List.Select returns a list).

Step D

At a high level, step D says: give me the other stuff in the first nested list (NOT the four text names) and convert it to number.

= List.Transform( List.Difference( B{0}, C ),Number.From)

Explore the syntax seen above/below.

List.Transform(list as list, transform as function) as list

Step A reminds us the other stuff is eight date values (aka numbers):

Step E

Yes, the M code in step E is challenging (get coffee) but we can do it!

 E = List.Transform( 
       List.Split( 
          List.Transform({0..List.Count(D)-1}, each D{_}+List.RemoveNulls( B{1}{_}),
          2
       )
       ,(x)=> (x{1}-x{0})*24
     )

We’ll break it into three parts:

Step E inner part

List.Transform({0..List.Count(D)-1}, each D{_}+List.RemoveNulls(B{1}{_})

List.Transform wants a list then an action on the list then return a new list

List.Transform(list as list, transform as function) as list

I wanted to see what it produced so I created step D.E.1:

Integer values (e.g. 45566) are dates. It adds time portion (day fraction between 0 and 1) to the integer! Now I know WHAT it creates but HOW?

The list (inside List.Transform) part below creates a list from 0 to 7:

{0..List.Count(D)-1}

Below, ={0..7} creates list, always 0 to 7 Above, it’s dynamic via count function ={0..List.Count(D)-1}

This is perhaps the only part that I don’t 100% understand…but I think of it as creating eight rows so we can add eight date (integers) and time (decimals) values together.

Now, let’s see exactly what transform as function does:

each D{_}+List.RemoveNulls( B{1}{_})

Key: we’ve been dealing with the first nested list from step B (dates). Now, Kris is extracting time values from the second nested list in step B. Function List.RemoveNulls removes the nulls.

I created another mini query to see this isolated part:

Step E middle part

=List.Split(D.E.1,2)

List.Split wants a list then an action on the list then return a new list

List.Split(list as list, pageSize as number) as list

pageSize as number is 2 (two per nested list). To see it, I created this:

It’s easy to forget why we’re doing all this. Remember: per person, subtract start date time from end date time to create time duration!

List.Split creates four nested lists, one per person, with start date time and end date time inside each one. Above, I selected the first nested list so we can see it’s two values (bottom left).

Step E outer part

Each end date time – start date time. Multiply that amount by 24:

List.Transform wants a list then an action on the list then return a new list
List.Transform(list as list, transform as function) as list
(x)=> (x{1}-x{0})*24

What does (x)=> do? It says: let’s create a function called x, subtract the first nested item (start date time) from the second nested item (end date time), multiply that by 24.

I recommend Mike Girvin’s book to learn Power Query function syntax (and P.Q. in general):

Step E’s final result is:

Step F

Table.FromColumns puts the steps together for the final answer.

=Table.FromColumns({C,E},{"Name","Duration"})
Table.FromColumns(lists as list, optional columns as any) as table

After a lot of List functions Kris uses a Table function!

Recap

  • as an advanced user, Kris did a lot of work in step E by combining functions
  • also, Kris named his steps in a sequential manner (A, B, C, etc.) because that’s all he needed
  • Kris can read M code like a sentence! I’m not there yet so I did the following:
    • wrote new queries to see exactly what data a particular part created
    • studied Microsoft’s M function syntax
    • horizontally aligned M code to make it easier to read
    • added comments viewable in advanced editor and in Applied Steps (hover over “i”)

When initially auditing Kris’ M code, I sketched it out to help understand it:

I added comments, indentation, and carriage returns to Kris’ code:

let

//CONNECT TO TABLE1
 A = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],

//EACH COLUMN BECOMES A LIST ITEM
 B = Table.ToColumns(A),
 
//SELECT FIRST LIST AND EXTRACT TEXT VALUES 
 C = List.Select(B{0}, each Text.From(_)=_),
 
//EXTRACT DATE VALUES AND CONVERT TO NUMBER 
 D = List.Transform( List.Difference(B{0},C), Number.From),

//CALCULATE DURATION BETWEEN EACH PERSON'S DATE/TIME VALUES 
 E = List.Transform( 
                    List.Split( 
                               List.Transform({0..List.Count(D)-1}, each D{_}                                               
                               +List.RemoveNulls( B{1}){_}),
                               2
                    )
                    ,(x)=> (x{1}-x{0})*24
     ),

//CREATE A TABLE WITH TWO COLUMNS FROM STEPS C & E
 F = Table.FromColumns({C,E},{"Name","Duration"})

in
 F

After reviewing all the pieces, is the M code easier to read now? I hope so.

Here’s another Power Query solution by Kris for the same challenge!

let
 A = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
 B = Table.AddColumn(A, "Num", each Number.From([#"Name & Date"])+[Time]),
 C = Table.TransformColumns( B ,{"Name & Date" , each if Text.From(_) = _ then _ else null }),
 D = Table.FillDown(C,{"Name & Date"}),
 E = Table.Group(D, {"Name & Date"}, {"Duration", each ( [Num]{2} -[Num]{1})*24 })
in
 E

About Me

My name is Kevin Lehrbass. I’m a data analyst. I can *think* in Excel formulas easily. I’m training my brain more and more to *think* in M code and DAX…while also reviewing SQL and VBA!

Away from data, my other hobbies include: learning Spanish, playing chess, and drawing.

Formula Readability

We all know how easily things can get out of control when writing a complex formula. It may provide the correct answer, but will anyone understand it?

Read more: Formula Readability

A good definition from Copilot:

The clarity, simplicity, and interpretability of a formula, enabling users to quickly understand its purpose, logic, and components without needing extensive explanation.

Requirements

Given the data on the left, create the output on the right:

  • use a single formula
  • all parts horizontally aligned (column M) even if text length changes
  • include title “NHL 1980-1981 Season Round 1 Playoff Bracket”
  • copy/paste single formula to reuse solution

Yes, it would be MUCH easier to use five columns and align text as needed…but I wouldn’t get to use the LET function!

Solution 1

=VSTACK("NHL 1980-1981 Season Round 1 Playoff Bracket",
        LET(
        t, B3:B18,  s,B3:B10,
        M,MAX(LEN(s))+1,  N,MAX(LEN(t)),
        arrayI,{1;2;3;4;5;6;7;8},b,17-arrayI,
        arrayI&" "&INDEX(s&REPT(" ",M-LEN(s))&"vs ",arrayI)&
        INDEX(t&REPT(" ",N-LEN(t)),17-arrayI)&" "&IF(LEN(b)=1," "&b,b)))

At first I liked this formula due to it’s short length. When I went back later to change something, I realized it was difficult to audit.

Solution 2

LET function is amazing! It lets us reduce function names to a single letter:

=VSTACK("NHL 1980-1981 Season Round 1 Playoff Bracket",
LET(
t, B3:B18, s,B3:B10, X,MAX, L,LEN, I,INDEX, R,REPT,
m,X(L(s))+1, n,X(L(t)),
a,{1;2;3;4;5;6;7;8},b,17-a,
a&" "&I(s&R(" ",m-L(s))&"vs ",a)&
I(t&R(" ",n-L(t)),17-a)&" "&IF(L(b)=1," "&b,b)))

Shorter but even more difficult to audit! I like the idea of being kind to my future self when auditing/modifying a formula weeks or months in the future.

Solution 3

I finally settled on this formula. Much longer but kind šŸ™‚

=VSTACK("NHL 1980-1981 Season Round 1 Playoff Bracket",
LET(
TopTxt,B3:B10, EndTxt,B11:B18, RankA,{1;2;3;4;5;6;7;8}, RankB,17-RankA, RankC,RankB-8,

a,N("RankBB pushes rank 9 one additional space to the right"),
RankBB,IF(LEN(RankB)=1," "&RankB,RankB),

b,N("Calc longest text for top & bottom team sets. Pad others with spaces"),
LongTxtA,MAX(LEN(TopTxt)),
LongTxtB,MAX(LEN(EndTxt)),
PadA,REPT(" ",LongTxtA-LEN(TopTxt)),
PadB,REPT(" ",LongTxtB-LEN(EndTxt)+1),

c,N("Concatenate parts together"),
RankA&" "& INDEX(TopTxt&PadA,RankA)
&" vs " & INDEX(EndTxt&PadB,RankC)&RankBB))

Ideas I used in this formula:

  • longer descriptive variable names for ranges and calculations
  • ALT + ENTER for carriage returns (imagine without them!)
  • N function to comment a section of similar items (except 1st row of LET which I think is easy to read)
  • final formula: concatenates parts together (no additional calcs)
  • could I have used a single range along with TAKE function?

Update: use “comment1” etc as variable names (no need for N function). Thanks to Mahmoud Bani Asadi!

=VSTACK("NHL 1980-1981 Season Round 1 Playoff Bracket",
LET(
TopTxt,B3:B10, EndTxt,B11:B18, RankA,{1;2;3;4;5;6;7;8}, RankB,17-RankA, RankC,RankB-8,

comment1,"RankBB pushes rank 9 one additional space to the right",
RankBB,IF(LEN(RankB)=1," "&RankB,RankB),

comment2,"Calc longest text for top & bottom team sets. Pad others with spaces",
LongTxtA,MAX(LEN(TopTxt)),
LongTxtB,MAX(LEN(EndTxt)),
PadA,REPT(" ",LongTxtA-LEN(TopTxt)),
PadB,REPT(" ",LongTxtB-LEN(EndTxt)+1),

comment3,"Concatenate parts together",
RankA&" "& INDEX(TopTxt&PadA,RankA)
&" vs " & INDEX(EndTxt&PadB,RankC)&RankBB))

And this is why we share ideas! We all learn and we all win!

Recap

We all have different skills and preferences…but I don’t think anyone enjoys auditing mega formulas! Even if you don’t like your colleagues, you should be kind to your future self!

LET function’s ability to define reusable variables reminds me of DAX variables that breaks logic into smaller pieces.

  • How would you have solved this using a single formula? (leave a comment below)
  • What have I not mentioned that’s essential to my solution? (non formula related)

Have you ever?

Have you ever used CELL function’s width info_type? Check out sheet ‘easy solution’!

Hmm…I noticed that manually checking a column’s width is not always the same result as CELL function. AI gave me what seems to be a solid answer:

1980-1981 NHL Season and Playoffs

The NHL created playoff pairing based on overall team rank (not division or conference) for the 81 playoffs. It was fair, but my team got clobbered in the first round by the reigning and eventual repeat champions (1980s New York Islanders dynasty). Cub fans and Red Sox fans endured longer before finally winning again….one day it will happen.

About Me

My name is Kevin Lehrbass. I’m a data analyst. My other hobbies include: learning Spanish, playing chess, and drawing.

Why and how do formulas spill?

I used this post by Meganathan Elumalai to explore the transition from traditional formulas to spill formulas (formula results spill into multiple cells).

Read more: Why and how do formulas spill?

Meganathan’s requirements are clear:

Meganathan used a table in column B for the source items. In this post I’ll use a non table range (my Excel file includes both).

Formula1:

Cell D5 formula, in the picture above, is also listed below:

=IF(ISERR(SEARCH(D$4,$B5)),"",D$4)

Cell D5 Formula Description

Look for cell D4 search word (Apple) within cell B5. If doing this causes an error (Apple isn’t within cell B5), then display a blank (“”). If it is found then display cell D4 search word (Apple).

This is the traditional method to solve this. The formula is then dragged down and right as needed. There’s nothing wrong with this but now we have more options: a formula can spill answers into other cells without being dragged or copied!

Before looking at Formula2, I’ll explain two things in my Excel file:

Conditional Formatting

Cells with formulas are highlighted in green (see picture below) if the check box is checked:

  • Formula1 in cell D5 was dragged down to row 10 and across to column I so all cells are green
  • Formula2 in cell D17 automatically spills down to row 22! I dragged cell D17 formula to the right to cell I17. Each formula spills down to row 22 (without being dragged down!)

Search Words (fruit)

  • In range D4 to I4, search words (fruit) are typed in
  • In cell D16, an array constant formula spills fruit names to the right until cell I16. The only formula in range D16 to I16 is in cell D16

Formula2:

Cell D17 formula, in the picture above, is also listed below:

=IF(ISERR(SEARCH(D$16,$B$5:$B$10)),"",D$16)

As we saw earlier, SEARCH is typically used to look for a single cell value inside of another single cell (exception: array formulas) like this: SEARCH(D$4,$B5)

But, Formula2 SEARCH(D$16,$B$5:$B$10) searches for Apple in a range of cells: $B$5 to $B$10 creating multiple answers. Cell D17 formula spills down to cell B22 as range $B$5:$B$10 has 6 cells.

  • D17 formula: cell D16 search word Apple is in cell B5 so display Apple
  • D17 formula spills to cell D18: cell D16 search word Apple isn’t in cell B6 so blank
  • D17 formula spills to cell D19: cell D16 search word Apple is in cell B7 so display Apple
  • D17 formula spills to cell D20: cell D16 search word Apple isn’t in cell B8 so blank
  • D17 formula spills to cell D21: cell D16 search word Apple is in cell B9 so display Apple
  • D17 formula spills to cell D22: cell D16 search word Apple isn’t in cell B10 so blank

Cell D17 formula is then dragged right until cell I17.

Remember: only cells with green background have a formula. Other cells receive spill formula results or have typed in text values.

Formula3:

The formula in cell D29 is listed below:

=IF(ISERR(SEARCH(D28#,$B$5:$B$10)),"",D28#)
  1. cell D28 has an array constant formula that spills search words right to cell I28
  2. cell D29 has # after both D28 cell references (D28#) telling it to spill right as wide as the spill range of the array constant above
  3. cell D29 SEARCH function has a multi cell within_text argument range ($B$5:$B$10) causing it to spill down to row 34

Let’s validate this by changing cell D29 formula.

Remove the ability to spill right by changing D29 formula to this:

=IF(ISERR(SEARCH(D28,$B$5:$B$10)),"",D28)

    Remove the ability to spill down by changing D29 formula to this:

    =IF(ISERR(SEARCH(D28#,$B5)),"",D28#)

    Formula4:

    The formula in cell N4 is listed below:

    =LET(
    header,{"Apple","Banana","Grape","Kiwi","Orange","Pear"},
    formula,IF(ISERR(SEARCH(header,$B$5:$B$10)),"",header),
    VSTACK(header,formula))
    • LET function lets us define a name for a calculation (or array constant)
    • the name header has this formula: {“Apple”,”Banana”,”Grape”,”Kiwi”,”Orange”,”Pear”}
    • the name formula has this formula: IF(ISERR(SEARCH(header,$B$5:$B$10)),””,header)
    • VSTACK function vertically stacks these two spill pieces together

    Formula5:

    The formula in cell N16 is listed below:

    =LET(
    header,Fruit,
    formula,IF(ISERR(SEARCH(header,$B$5:$B$10)),"",header),
    VSTACK(header,formula))

    Formula6:

    The formula in cell N29 is listed below:

    =DROP(REDUCE(0,B5:B10,LAMBDA(a,i,VSTACK(a,MAP(D4:I4,LAMBDA(x,IF(ISNUMBER(FIND(x,i)),x,"")))))),1)

    Yes…but I can’t explain this formula yet. It was created by Excel MVP Rick Rothstein. It combines a lot of dynamic array functions so I definitely want to study it!

    About Me

    My name is Kevin Lehrbass. I’m a data analyst.

    Formulas that spill results into other cells are very powerful and have changed the way we build Excel models. They require special attention as they can also cause issues if not designed and tested carefully.

    Blendtec company founder Tom Dickson experiments to see what his blender can chop up. Microsoft Excel formulas are like that too…we have to study and experiment to see what they can do!