A generalised Lambda helper function that return arrays of arrays using bisection.

Silver Contributor

 

Specifically this required days of the week to be sorted by multiple price criteria.

[This is intended as a topic for discussion as opposed to a specific request for help]

 

I used the problem to develop a Lambda function that uses a binary tree to select the rows at the leaf nodes and perform a straightforward sort.  The results then get stacked pairwise until the blue table of results is returned

image.png

 

 

BYROWλ
"Applies a user-defined function by row and collects array results into a stacked array"
=LET(resultϑ, BYROW(array, ThunkFnλ), BinaryTreeλ(ROWS(resultϑ), "", Derefϑarrλ))

 

 

The main bisection recursion is hidden from the user

 

 

BinaryTreeλ
"Generates binary numbers stacking blocks pairwise to an upper limit"
=LET(
    maxNode, BASE(nodeCount - 1, 2),
    maxLevel, LEN(maxNode),
    level, LEN(parentNode),
    maxChild, LEFT(maxNode, 1 + level),
    IF(
        level < maxLevel - 1,
        LET(
            childNode0, BinaryTreeλ(nodeCount, parentNode & 0, FNλ),
            childNode1, BinaryTreeλ(nodeCount, parentNode & 1, FNλ),
            IF((parentNode & 0) = maxChild, childNode0, VSTACK(childNode0, childNode1))
        ),
        IF(
            (parentNode & 0) = maxChild,
            FNλ(parentNode & 0),
            VSTACK(FNλ(parentNode & 0), FNλ(parentNode & 1))
        )
    )
)

 

 

but it is intended to non-problem specific and hence reusable.

A key feature is that the user provides a Lambda function that performs the required calculation as if BYROW would return the result, but the function is converted to one the returns a thunk and hence avoids the array of arrays problem.

 

 

ThunkFnλ
"Accepts a user-defined Lambda function that returns an array result and generates a related function that returns the corresponding thunk"
=LAMBDA(arr, LAMBDA(userFnλ(arr)))

 

 

Finally

 

 

Derefϑarrλ
"Dereferences a term from a thunk array using a zero-based binary pointer and expands the resulting scalar thunk"
=INDEX(resultϑ, DECIMAL(ptr, 2) + 1, 1)()

 

 

converts the binary node pointer to a decimal index.

 

This is all crazily heavy but, hopefully, would be simple to reuse for other problems since the main processing is problem independent.

21 Replies

@Peter Bartholomew 

 

I am working on a different problem at the moment, but here is my general approach to some array manipulation via loops.  There are some background functions needed to make this work, but the overall theory/structure should be there to follow.  The parameterization of arguments isn't necessary, it is just a consequence of my overall design pattern.

/ loops

forList = 
lambda(
    forList_args,
    let(
        stack_bool, encap.unstuffSelected(forList_args,3),
        stuffed, forList.stuff(forList_args),
        result,
            if(
                stack_bool,
                colStuffedElements.unstuffAndStack(
                    encapthree(
                        stuffed,
                        encap.unstuffSelected(forList_args,5),
                        encap.unstuffSelected(forList_args,4)
                    )
                ),
                stuffed
        ),
        result
    )
);

forList.args = 
lambda(
        array, 
        function, 
        [stack_bool_df_false], 
        [hstack_bool_df_false],
        [padding_rows_cols_int_df_0],
        let(
            adj_array, take(ifs(arr.isColLike(array), array, arr.isSingleRow(array), transpose(array),1,index("Invalid array provided to forList.args.",1,1)),,1),
            stack_bool, if(isomitted(stack_bool_df_false),FALSE,stack_bool_df_false),
            hstack_bool, if(isomitted(hstack_bool_df_false), FALSE, hstack_bool_df_false),
            padding_rows_cols, if(isomitted(padding_rows_cols_int_df_0), 0, padding_rows_cols_int_df_0),
            encap(5, adj_array, function, stack_bool, hstack_bool, padding_rows_cols)
    )
);

forList.stuff = 
lambda(
    forList_args,
    let(
        array, encap.unstuffSelected(forList_args,1),
        function, encap.unstuffSelected(forList_args,2),
        result,
        map(array, lambda(ele, stuff(function(ele)))),
        result
    )
);

forRange = 
lambda(
    forRange_args,
    forList(forRange_args)
);

forRange.args = 
    lambda(
        no_of_loops, 
        function, 
        [stack_bool_df_false], 
        [hstack_bool_df_false],
        [padding_rows_cols_int_df_0],    
        [start_no_df_1],
        let(
            stack_bool, if(isomitted(stack_bool_df_false),FALSE,stack_bool_df_false),
            hstack_bool, if(isomitted(hstack_bool_df_false), FALSE, hstack_bool_df_false),
            start_no, if(isomitted(start_no_df_1), 1, start_no_df_1),
            padding_rows_cols, if(isomitted(padding_rows_cols_int_df_0), 0, padding_rows_cols_int_df_0),
            encap(5, sequence(no_of_loops,1,start_no), function, stack_bool, hstack_bool, padding_rows_cols)
            )
);


forRows = 
lambda(
    forRows_args,
    let(
        stack_bool, encap.unstuffSelected(forRows_args,3),
        stuffed, forRows.stuff(forRows_args),
        result,
            if(
                stack_bool,
                colStuffedElements.unstuffAndStack(
                    encapthree(
                        stuffed,
                        encap.unstuffSelected(forRows_args,5),
                        encap.unstuffSelected(forRows_args,4)
                    )
                ),
                stuffed
        ),
        result
    )
);

forCols = 
lambda(
    forCols_args,
    let(
        stack_bool, encap.unstuffSelected(forCols_args,3),
        stuffed, transpose(forCols.stuff(forCols_args)),
        result,
            if(
                stack_bool,
                colStuffedElements.unstuffAndStack(
                    encapthree(
                        stuffed,
                        encap.unstuffSelected(forCols_args,5),
                        encap.unstuffSelected(forCols_args,4)
                    )
                ),
                stuffed
        ),
        result
    )
);

forRows.args = 
lambda(
        array, 
        function, 
        [stack_bool_df_false], 
        [hstack_bool_df_false],
        [padding_rows_cols_int_df_0],

        let(
            stack_bool, if(isomitted(stack_bool_df_false),FALSE,stack_bool_df_false),
            hstack_bool, if(isomitted(hstack_bool_df_false), FALSE, hstack_bool_df_false),
            padding_rows_cols, if(isomitted(padding_rows_cols_int_df_0), 0, padding_rows_cols_int_df_0),
            encap(5, array, function, stack_bool, hstack_bool, padding_rows_cols)
    )
);


forRows.stuff = 
lambda(
    forRows_args,
    let(
        array, encap.unstuffSelected(forRows_args,1),
        function, encap.unstuffSelected(forRows_args,2),
        result,
        byrow(array, lambda(row, stuff(function(row)))),
        result
    )
);

forCols.args = 
lambda(
        array, 
        function, 
        [stack_bool_df_false], 
        [hstack_bool_df_false],
        [padding_rows_cols_int_df_0], 
        let(
            stack_bool, if(isomitted(stack_bool_df_false),FALSE,stack_bool_df_false),
            hstack_bool, if(isomitted(hstack_bool_df_false), FALSE, hstack_bool_df_false),
            padding_rows_cols, if(isomitted(padding_rows_cols_int_df_0), 0, padding_rows_cols_int_df_0),
            encap(5, array, function, stack_bool, hstack_bool, padding_rows_cols)
    )
);

forCols.stuff =
lambda(
    forCols_args,
    let(
        array, encap.unstuffSelected(forCols_args,1),
        function, encap.unstuffSelected(forCols_args,2),
        result,
        bycol(array, lambda(col, stuff(function(col)))),
        result
    )
);

 

@joelb95 

 

And in case anyone wants a bit more detail on the background tasks - here is an implementation of the main stuffing/encapsulation logic and a demonstration of stacking arrays of arrays with padding.

 

// stuffing for dynamic number of elements data passing
stuff = lambda(array, lambda(x, choose(x, array)));
unstuff = lambda(stuffed_array, stuffed_array(1));

//encap for static number of elements parameter passing

encap = 
lambda(
    num_elements, 
    p_1, [p_2], [p_3], [p_4], [p_5], [p_6], [p_7], [p_8], [p_9], [p_10], 
    [p_11], [p_12], [p_13], [p_14], [p_15], [p_16], [p_17], [p_18], [p_19], [p_20], 
    [p_21], [p_22], [p_23], [p_24], [p_25], [p_26], [p_27], [p_28], [p_29], [p_30], 
    [p_31], [p_32], [p_33], [p_34], [p_35], [p_36], [p_37], [p_38], [p_39], [p_40],
    lambda(
        choice, 
        choose(
            choice+1, 
            num_elements, 
            stuff(p_1), stuff(p_2), stuff(p_3), stuff(p_4), stuff(p_5), stuff(p_6), stuff(p_7), stuff(p_8), 
            stuff(p_9), stuff(p_10), stuff(p_11), stuff(p_12), stuff(p_13), stuff(p_14), stuff(p_15), stuff(p_16), 
            stuff(p_17), stuff(p_18), stuff(p_19), stuff(p_20), stuff(p_21), stuff(p_22), stuff(p_23), stuff(p_24), 
            stuff(p_25), stuff(p_26), stuff(p_27), stuff(p_28), stuff(p_29), stuff(p_30), stuff(p_31), stuff(p_32), 
            stuff(p_33), stuff(p_34), stuff(p_35), stuff(p_36), stuff(p_37), stuff(p_38), stuff(p_39), stuff(p_40)
        )
    )
);

// for vstacking or hstacking arrays that are contained in a unidimensional array (unitary cell, single row, or single column). Variations for encapsulated rows/columns also exist.

colStuffedElements.unstuffAndStack = 
lambda( 
    encapthree_colStuffedElements_paddingColOrRowInt_hstackBoolDefaultFalse,
    let(
        col_stuffed_elements, encap.unstuffFirstElement(encapthree_colStuffedElements_paddingColOrRowInt_hstackBoolDefaultFalse),
        padding_col_or_row, encap.unstuffSecondElement(encapthree_colStuffedElements_paddingColOrRowInt_hstackBoolDefaultFalse),
        hstack_bool, encap.unstuffThirdElement(encapthree_colStuffedElements_paddingColOrRowInt_hstackBoolDefaultFalse),
        if(
            hstack_bool,
            colStuffedElements.unstuffAndHSTACK(col_stuffed_elements,padding_col_or_row),
            colStuffedElements.unstuffAndVSTACK(col_stuffed_elements,padding_col_or_row)
        )
    )
);

colStuffedElements.unstuffAndHSTACK = 
lambda(
    colOfStuffedElements,
    [seperator_cols],
    let(
        seperator_pad, EXPAND("", , seperator_cols, ""),
        pad_original, IF(
            or(isomitted(seperator_cols), seperator_cols = 0),
            LAMBDA(padded_orig, expandTo, padded_orig),
            LAMBDA(padded_orig, expandTo, HSTACK(padded_orig, EXPAND(seperator_pad, expandTo, , "")))
        ),
        result, 
            DROP(
                REDUCE(
                    "",
                    SEQUENCE(rows(colOfStuffedElements)),
                    LAMBDA(acc, cur,
                                LET(
                                    original, acc,
                                    new, unstuff(index(colOfStuffedElements,cur,1)),
                                    expand_to, MAX(ROWS(original), ROWS(new)),
                                    expanded_original, EXPAND(original, expand_to, , ""),
                                    padded_orig, pad_original(expanded_original, expand_to),
                                    HSTACK(padded_orig, EXPAND(new, expand_to, , ""))
                        )
                    )
                ),
                0,(1+seperator_cols)
        ),
        result
    )        
);

colStuffedElements.unstuffAndVSTACK =
lambda(
    colOfStuffedElements,
    [seperator_rows],
    let(
        
        seperator_pad, EXPAND("", seperator_rows, , ""),
        pad_original, IF(
            or(isomitted(seperator_rows), seperator_rows = 0),
            LAMBDA(padded_orig, expandTo, padded_orig),
            LAMBDA(padded_orig, expandTo, VSTACK(padded_orig, EXPAND(seperator_pad, , expandTo, "")))
        ),
        result, 
            DROP(
                REDUCE(
                    "",
                    SEQUENCE(ROWS(colOfStuffedElements)),
                    LAMBDA(acc, cur,

                                LET(
                                    original, acc,
                                    new, unstuff(index(colOfStuffedElements,cur,1)),
                                    expand_to, MAX(COLUMNS(original), COLUMNS(new)),
                                    expanded_original, EXPAND(original, , expand_to, ""),
                                    padded_orig, pad_original(expanded_original, expand_to),
                                    VSTACK(padded_orig, EXPAND(new, , expand_to, ""))
                                
                            
                        )
                    )
                ),
                (1 + seperator_rows)
        ),
        result
    )
        
);