Last active
June 15, 2023 09:21
-
-
Save ncalm/0b9ed37625152a45a5118ee789921854 to your computer and use it in GitHub Desktop.
This Excel lambda namespace provides functionality for creating arrays of functions and sequential vector transforms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************************************************************************** | |
****************************************************************************************** | |
Array of functions | |
****************************************************************************************** | |
Allows for creation of an array of functions which can be passed as a parameter to another function | |
Original credit to: Travis Boulden | |
https://www.mrexcel.com/board/threads/ifanyof.1184234/ | |
Function named "either" on that page | |
In the code below, I have simplified slightly to use VSTACK instead of CHOOSE | |
and SUM instead of REDUCE to calculate the count of not-omitted functions | |
e.g. Apply the SQRT, LN and LOG_10 transformations to the wine vector: | |
=LAMB.TRANSFORM(wine, LAMB.FUNCS(LAMB.SQRT, LAMB.LN, LAMB.LOG_10)) | |
Issue here is if we provide fn_1, don't provide fn_2, then provide fn_3, it will try to return | |
an array containing fn_1 and fn_2 | |
*/ | |
FUNCS =LAMBDA( | |
fn_1,[fn_2],[fn_3],[fn_4],[fn_5], | |
[fn_6],[fn_7],[fn_8],[fn_9],[fn_10], | |
LET( | |
//An array indicating which functions are omitted | |
omitted_fns, | |
VSTACK( | |
ISOMITTED(fn_1),ISOMITTED(fn_2), | |
ISOMITTED(fn_3),ISOMITTED(fn_4), | |
ISOMITTED(fn_5),ISOMITTED(fn_6), | |
ISOMITTED(fn_7),ISOMITTED(fn_8), | |
ISOMITTED(fn_9),ISOMITTED(fn_10) | |
), | |
//count of the not omitted functions | |
fn_ct,SUM(--NOT(omitted_fns)), | |
//return the first fn_ct functions in an array | |
fns, | |
CHOOSE(SEQUENCE(fn_ct), | |
fn_1,fn_2,fn_3,fn_4,fn_5, | |
fn_6,fn_7,fn_8,fn_9,fn_10 | |
), | |
fns | |
) | |
); | |
/* | |
Author: OWEN PRICE | |
Date: 2022-08-27 | |
Apply a single function to each column in an array. | |
The function may produce multiple output columns per data-column | |
This approach uses iteration. Other approaches are available :) | |
*/ | |
BYCOL =LAMBDA(data, fn, [output], | |
LET( | |
//get the first column to apply the function to | |
_v, TAKE(data,,1), | |
//get the remaining columns | |
_rem, DROP(data,,1), | |
//apply the function to the first column and get the results | |
_applied, fn(_v), | |
//stack the new results with the results of the previous columns (or nothing if this is first iteration) | |
_stacked, IF(ISOMITTED(output), _applied, HSTACK(output, _applied)), | |
//if data currently only has one column, then just return the stack, otherwise iterate using _rem=data | |
_output, IF(COLUMNS(data)=1,_stacked,LAMB.BYCOL(_rem, fn, _stacked)), | |
_output | |
) | |
); | |
/***************************************************************************************** | |
****************************************************************************************** | |
Library of transformation lambdas | |
****************************************************************************************** | |
Author: OWEN PRICE | |
Date: 2022-08-27 | |
Examples of simple vector transforms that can be applied sequentially using LAMB.TRANSFORM | |
*/ | |
//Wraps the SQRT function as a lambda so it can be passed around other functions | |
SQRT = LAMBDA(vector, SQRT(vector)); | |
//Wraps the LN function as a lambda so it can be passed around other functions | |
LN = LAMBDA(vector, LN(vector)); | |
/* | |
Returns a lambda of the LOG at the specified base | |
The returned lambda can then be passed to other functions | |
To create a "log base 10" function: | |
=outlier.log(10) | |
To use that function with a vector v: | |
=outlier.log(10)(v) | |
*/ | |
LOG = LAMBDA(base, LAMBDA(vector, LOG(vector, base))); | |
//For simplicity, create a lambda function for applying the log10 transform to a vector | |
LOG_10 = LAMBDA(vector, LAMB.LOG(10)(vector)); | |
//Returns a lambda function that raises a vector to the given power | |
POWER = LAMBDA(exponent, LAMBDA(vector, POWER(vector, exponent))); | |
RECIPROCAL = LAMBDA(vector, LAMB.POWER(-1)(vector)); | |
RECIPROCAL_SQ = LAMBDA(vector, LAMB.POWER(-2)(vector)); | |
CUBEROOT = LAMBDA(vector, LAMB.POWER(1/3)(vector)); | |
/* | |
Author: OWEN PRICE | |
Date: 2022-08-27 | |
Used to transform a vector once for each transformation function in transform_fns | |
e.g. transform the 'wine' vector using SQRT, LN and LOG10 | |
=LAMB.TRANSFORM(vector, LAMB.FUNCS(LAMB.SQRT, LAMB.LN, LAMB.LOG_10)) | |
*/ | |
TRANSFORM =LAMBDA(vector,transform_fns, | |
REDUCE(vector,transform_fns,LAMBDA(a,b,HSTACK(a,b(vector)))) | |
); | |
/* | |
BETWEEN | |
Author: Owen Price | |
Date: 2022-09-10 | |
Returns a lambda that itself returns TRUE if the vector value is >=gteq (the lower boundary) | |
or the vector value is <=lteq (the upper boundary) | |
*/ | |
BETWEEN =LAMBDA(gteq,lteq, LAMBDA(vector, IFERROR(( (vector>=gteq) * (vector<=lteq) ) > 0, FALSE))); | |
/* | |
ROTATE | |
Author: Owen Price | |
Date: 2022-09-10 | |
Rotates a 2-dimensional array anti-clockwise by 90 degrees. | |
This is not the same behavior as TRANSPOSE, which reflects an array on the main diagonal | |
from top-left to bottom-right. | |
Inputs: | |
- arr - the input array | |
- times - the number of times to rotate by 90 degrees | |
- [iter] - optional - used as a counter by the recursion | |
Note: iter should not be used when calling this function from a spreadsheet | |
*/ | |
ROTATE = LAMBDA(arr,times,[iter], | |
LET( | |
_times,MOD(times,4), | |
IF(_times=0,arr, | |
LET( | |
_iter,IF(ISOMITTED(iter),1,iter), | |
_cols,COLUMNS(arr), | |
_rotated,INDEX(arr,SEQUENCE(1,ROWS(arr)),_cols-SEQUENCE(_cols)+1), | |
IF(_iter=_times,_rotated,ROTATE(_rotated,_times,_iter+1)) | |
) | |
) | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment