SOLVED

Default values for LAMBDA paramters - Part II

%3CLINGO-SUB%20id%3D%22lingo-sub-2223471%22%20slang%3D%22en-US%22%3EDefault%20values%20for%20LAMBDA%20paramters%20-%20Part%20II%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2223471%22%20slang%3D%22en-US%22%3E%3CP%3EBased%20on%20the%20responses%20%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fexcel%2Fdefault-values-for-lambda-parameters%2Fm-p%2F2214212%22%20target%3D%22_self%22%3Eto%20this%20question%2C%3C%2FA%3E%20I%20decided%20to%20try%20the%20answer%20out%20on%20a%20function%20I%20picked%20up%20somewhere%2C%20which%20splits%20a%20string%20based%20on%20a%20specified%20delimiter.%3C%2FP%3E%3CP%3EUsing%20a%20LAMBDA%20function%20without%20default%20parameters%2C%20and%20feeding%20it%20the%20two%20parameters%20(the%20string%20-%20several%20words%20with%20space%20between%20them%2C%20specified%20in%20A1%20-%20and%20the%20delimiter%20-%20space%2C%20for%20this%20example)%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-applescript%22%3E%3CCODE%3E%3DLAMBDA(string%2Cdelimiter%2C%20%0ATRANSPOSE(FILTERXML(%22%3CT%3E%3CS%3E%22%20%26amp%3B%20SUBSTITUTE(string%2C%20delimiter%2C%20%22%3C%2FS%3E%3CS%3E%22)%20%26amp%3B%20%22%3C%2FS%3E%3C%2FT%3E%22%2C%20%20%22%2F%2Fs%22)%20)%20%0A)(A1%2C%22%20%22)%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3Eeverything%20works%20as%20expected.%3C%2FP%3E%3CP%3ESetting%20space%20as%20the%20default%20parameter%20and%20NOT%20including%20it%20in%20the%20parameters%20submitted%2C%20also%20works%20as%20expected%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-applescript%22%3E%3CCODE%3E%3DLAMBDA(string%2Cdelimiter%2C%0ATRANSPOSE(%0A%20%20%20%20FILTERXML(%0A%20%20%20%20%20%20%20%20%22%3CT%3E%3CS%3E%22%20%26amp%3B%0A%20%20%20%20%20%20%20%20SUBSTITUTE(%0A%20%20%20%20%20%20%20%20%20%20%20%20string%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20IF(delimiter%2Cdelimiter%2C%22%20%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2FS%3E%3CS%3E%22%0A%20%20%20%20%20%20%20%20)%20%26amp%3B%20%22%3C%2FS%3E%3C%2FT%3E%22%2C%0A%20%20%20%20%20%20%20%20%22%2F%2Fs%22%0A%20%20%20%20)%0A)%0A)(A1%2C)%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHowever%2C%20feeding%20both%20parameters%20to%20the%20same%20LAMBDA%20(whether%20the%20delimiter%20is%20space%20or%20anything%20else)%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-applescript%22%3E%3CCODE%3E(A1%2C%22%20%22)%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3Eraises%20a%20%23VALUE!%20error.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWhat%20to%20do%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-2223471%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EExcel%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2223541%22%20slang%3D%22en-US%22%3ERe%3A%20Default%20values%20for%20LAMBDA%20paramters%20-%20Part%20II%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2223541%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F968780%22%20target%3D%22_blank%22%3E%40JackTradeOne%3C%2FA%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThat's%20since%20%3CSTRONG%3EIF(%22text%22%2C%20...%3C%2FSTRONG%3E%20returns%20%23VALUE!.%20In%20previous%20sample%20I%20assumed%20using%20of%20numbers.%3C%2FP%3E%0A%3CP%3EHere%20you%20may%20change%20on%26nbsp%3B%3CSTRONG%3EIF(delimiter%26lt%3B%26gt%3B0%2Cdelimiter%2C%22%20%22)%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%3EAs%20a%20comment%2C%20I'd%20do%20not%20recommend%20to%20use%20FILTERXML%20as%20general%20function%20for%20splitting%20the%20text%2C%20only%20if%20we%20assume%20if%20the%20text%20has%20no%20inside%20some%20special%20symbols%20which%20are%20not%20recognized%20by%20this%20function.%20For%20example%2C%20splitting%20of%26nbsp%3B%20%3CSTRONG%3Ea%2Cb%26amp%3Bc%2Cd%3C%2FSTRONG%3E%20returns%20an%20error%20since%20instead%20of%20%3CSTRONG%3E%26amp%3B%3C%2FSTRONG%3E%20you%20shall%20use%26nbsp%3B%3CSTRONG%3E%26amp%3Bamp%3B%3C%2FSTRONG%3E%20.%20Similar%20for%20some%20other%20characters.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2223717%22%20slang%3D%22en-US%22%3ERe%3A%20Default%20values%20for%20LAMBDA%20paramters%20-%20Part%20II%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2223717%22%20slang%3D%22en-US%22%3E%3CP%3EThanks!%20I%20didn't%20realize%3CSTRONG%3E%20IF(%22TEXT%22%2C...%3C%2FSTRONG%3E%20raises%20an%20error.%20I'll%20use%20your%20suggestion%20or%20%3CSTRONG%3EIF(delimiter%26lt%3B%26gt%3B%22%22%2Cdelimiter%2C%22%20%22)%3C%2FSTRONG%3E.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAs%20to%20your%20comment%20about%20the%20problem%20with%20using%20FILTERXML%20to%20split%20strings%20by%20delimiter%20-%20I%20definitely%20agree%2C%20but%20I%20have%20to%20say%20this%20is%20the%20only%20solution%20I%20know%20of%20to%20do%20that%20for%20strings%20with%20more%20than%20two%20delimiters%20(those%20can%20be%20split%20with%20RIGHT%2C%20LEFT%2C%20MID).%20It's%20really%20strange%20that%20something%20as%20basic%20as%20this%2C%20which%20in%20(for%20example)%20python%20and%20javascript%20can%20be%20accomplished%20with%20something%20as%20simple%20as%20%3CSTRONG%3Estring.split(%22%20%22)%3C%2FSTRONG%3E%20requires%20people%20to%20resort%20to%20gymnastics%20such%20as%20converting%20the%20string%20to%20xml%2C%20running%20an%20xpath%20expression%20on%20it%20and%20then%20transposing%20the%20output...%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2224201%22%20slang%3D%22en-US%22%3ERe%3A%20Default%20values%20for%20LAMBDA%20paramters%20-%20Part%20II%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2224201%22%20slang%3D%22en-US%22%3EVBA%20also%20has%20a%20split%20function.%20Maybe%20you%20could%20make%20a%20user%20defined%20wrapper%20function%20for%20it%20and%20use%20that%20instead%20of%20filterxml%3F%3C%2FLINGO-BODY%3E
Occasional Contributor

Based on the responses to this question, I decided to try the answer out on a function I picked up somewhere, which splits a string based on a specified delimiter.

Using a LAMBDA function without default parameters, and feeding it the two parameters (the string - several words with space between them, specified in A1 - and the delimiter - space, for this example):

 

=LAMBDA(string,delimiter, 
TRANSPOSE(FILTERXML("<t><s>" & SUBSTITUTE(string, delimiter, "</s><s>") & "</s></t>",  "//s") ) 
)(A1," ")

 

everything works as expected.

Setting space as the default parameter and NOT including it in the parameters submitted, also works as expected:

 

=LAMBDA(string,delimiter,
TRANSPOSE(
    FILTERXML(
        "<t><s>" &
        SUBSTITUTE(
            string,
            IF(delimiter,delimiter," "),
            "</s><s>"
        ) & "</s></t>",
        "//s"
    )
)
)(A1,)

 

However, feeding both parameters to the same LAMBDA (whether the delimiter is space or anything else):

 

(A1," ")

 

 

raises a #VALUE! error.

 

What to do?

10 Replies
best response confirmed by JackTradeOne (Occasional Contributor)
Solution

@JackTradeOne 

That's since IF("text", ... returns #VALUE!. In previous sample I assumed using of numbers.

Here you may change on IF(delimiter<>0,delimiter," ")

As a comment, I'd do not recommend to use FILTERXML as general function for splitting the text, only if we assume if the text has no inside some special symbols which are not recognized by this function. For example, splitting of  a,b&c,d returns an error since instead of & you shall use &amp; . Similar for some other characters.

Thanks! I didn't realize IF("TEXT",... raises an error. I'll use your suggestion or IF(delimiter<>"",delimiter," ").

 

As to your comment about the problem with using FILTERXML to split strings by delimiter - I definitely agree, but I have to say this is the only solution I know of to do that for strings with more than two delimiters (those can be split with RIGHT, LEFT, MID). It's really strange that something as basic as this, which in (for example) python and javascript can be accomplished with something as simple as string.split(" ") requires people to resort to gymnastics such as converting the string to xml, running an xpath expression on it and then transposing the output...

VBA also has a split function. Maybe you could make a user defined wrapper function for it and use that instead of filterxml?

@JackTradeOne 

 

Here's my latest iteration implementing a text split LAMBDA; you can provide a delimiter to split on, or if you leave that parameter blank, it splits on each char:

=LAMBDA(str,del,
    LET(
        dsd,del&str&del,
        posArray,
            IF(
                ISBLANK(del),SEQUENCE(LEN(str)+1),
                FIND(
                    CHAR(1),
                    SUBSTITUTE(
                        dsd,
                        del,
                        CHAR(1),
                        SEQUENCE((LEN(dsd)-LEN(SUBSTITUTE(dsd,del,"")))/LEN(del))
                    )
                )
            )-1,
        startPosArray,INDEX(posArray,SEQUENCE(ROWS(posArray)-1)),
        splitPosArray,INDEX(posArray,SEQUENCE(ROWS(posArray)-1,1,2,1)),
        charArray,MID(str,startPosArray+1,splitPosArray-startPosArray-LEN(del)),
        valArray,IFERROR(VALUE(charArray),charArray),
        valArray
    )
)

 

@tboulden 

Couple of cosmetics: it splits vertically, more logical horizontally (however that cold be defined by parameter) and if separator is not defined it splits on characters. I'd suggest

=LAMBDA(str,del,
  LET(
   sep, IF(del=0,",",del),

   TEXTCountSeps,
       LAMBDA(str,sep,
          SUM(
             LET(
               n, LEN(str),
               k, SEQUENCE(n),
              IF(n=0, "", 1*(MID(str,k,1)=sep))
         ))
   ),

   TextSepPositions,
     LAMBDA(str,sep,up,
        LET(
           n,   LEN(str),
           k,   SEQUENCE(,n+up,up),
           arr, IF(k>n, n,
                   IFERROR( IF(
                               1*(MID(str,k,1)=sep),
                               k+1-2*up,
                               0 ),
                     1) ),
        FILTER(arr,arr)
      )
   ),

    TextSplit, LAMBDA(str,sep,
         LET(
               start, TextSepPositions(str, sep, 0),
               end,   TextSepPositions(str, sep, 1),
               TRIM(MID(str, start, end-start+1))
       )
     ),
TextSplit(str, sep)
))

 

Hi Sergei, very nice, I'll review more in depth, however your version assumes comma if delimiter isn't provided, mine splits on each char if not provided; also, mine handles delimiters where LEN(del)>1. I like to handle this case because sometimes I want to be sure I'm not splitting on part of my string inadvertently; I like to do TEXTJOIN with #@# or similar in case there is # or @ in cells.

@tboulden 

You are right, that's limited version. I have couple more, with separator as text string and another one which ignores separators within the quotes. For example, "a,b",c  will be split on a,b | c , not on a | b | c.

 

So far didn't merge all variants in one universal functions, still hope native TEXTSPLIT() appears in Excel.

Yes, I would like very much if we get a native function, and it may be wishful thinking to hope for native functions that handle regular expressions or similar! In the meantime, its good practice for me to come up with or see different versions and learn new ways of completing same task.

 


still hope native TEXTSPLIT() appears in Excel.


@Sergei Baklan 

I really hope that happens and happens soon. It's almost depressing to look at the size of the suggested LAMBDA functions necessary to perform such a basic task.

Indeed, but the whole idea was to create an internal Excel function without resorting to VBA, Office JS or whatever. I definitely don't like having to use FILTERXML (or any of the alternative proposed above) - it's ridiculous that we have to resort to this kind of trickery for something that should a built in function.