Subscribe Bookmark
Craige_Hales

Staff

Joined:

Mar 21, 2013

Head Arg Recurse Formula

8476_recursion.PNG

inspired by Is there a way to extract columns used in a formula? and Ian@JMPcomment.


dt = New Table( "Get Columns in Formula",


    Add Rows( 20 ),


    New Column( "H", Numeric, "Continuous", Format( "Best", 12 ), Formula( Random Uniform() ) ),


    New Column( "W", Numeric, "Continuous", Format( "Best", 12 ), Formula( Random Uniform() ) ),


    New Column( "D", Numeric, "Continuous", Format( "Best", 12 ), Formula( Random Uniform() ) ),


    New Column( "V", Numeric, "Continuous", Format( "Best", 12 ), Formula( (:W * :H * :D) / 10 ) )


);


formula = dt:V << getformula();


// function to find leaves in formula that are columns in the table


findColumns = Function( {frm, cols},


    {h = Head( frm ), n = N Arg( frm ), i, result = {}}, // local variables


    If( n == 0, // head node has no children, it is a leaf


        If( Contains( cols, Name Expr( h ) ), // is the leaf in the list of columns?


            Insert Into( result, Name Expr( h ) ); // yes -> add to result


        )


    ,


        For( i = 1, i <= n, i++, // not a leaf, get children's results


            Insert Into( result, Recurse( Arg( frm, i ), cols ) )


        )


    );


    result// return the result


);


answer = findColumns( Name Expr( formula ), dt << GetColumnNames );


Show( formula, answer );




formula = (:W * :H * :D) / 10;

answer = {:W, :H, :D};

The findColumns function defined on lines 10-22 takes two arguments, frm, the formula to examine, and cols, a list of valid column names to extract.  The Head of the example expression is Divide(...) which has two children (the answer from N Arg). The if statement sees there are children and uses the recurse function to process each child.  The multiply child has three children.  the :W child has no children, and the list of columns from the data table contains :W, so :W is inserted into a list and the list returned, where that list is inserted into a list.  The multiply child then sends the 2nd arg to recurse and :H is appended.  Eventually the 10 (the 2nd child of Divide) is sent to recurse, but isn't in the list of columns, so does not appear in the answer.

Recursion takes some effort every time.  But it makes a simple-looking program.

Article Tags