cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Browse apps to extend the software in the new JMP Marketplace
Choose Language Hide Translation Bar
Craige_Hales
Super User
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.

Last Modified: Dec 24, 2017 10:31 AM