cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
JMP is taking Discovery online, April 16 and 18. Register today and join us for interactive sessions featuring popular presentation topics, networking, and discussions with the experts.
Choose Language Hide Translation Bar
sornasst
Level III

Proper syntax to call Formula within Loop

Hi, I would like to quickly enter multiple columns with the same overall formula but different variables.

I have tried the following but clearly, I'm not using the proper syntax to call the Fomula item in the New Column function:

Names Default to Here (1);

dt = Current Data Table ();

cc = N col (dt); // Retain the original column number

For (i=9,i<= cc, i = i+2,

  New column ("Delta " || Column Name (i+1),

  numeric,

  continuous,

  Formula (:Column Name(i+1) - :Column Name (i)) // Problem with Syntax

  );

);

Thank you for your help.

Sincerely.

1 ACCEPTED SOLUTION

Accepted Solutions
Craige_Hales
Super User

Re: Proper syntax to call Formula within Loop

this script might build something close to what you are after.  the Formula parameter to the New Column function needs a completely built formula, in the form it needs to be in when it actually runs, which is after your script runs.  the eval( evalexpr( ... expr(...) ... expr(...) ... ) ) strategy below is one way to do what you need.  expr() is used to tag the parts that need to be evaluated.  evalexpr() hunts them down and evaluates them.  eval() evaluates the expression returned by evalexpr.  Note the minus between the two expr() is NOT evaluated inside the for loop, but names[i+1] IS evaluated (by evalexpr) and NewColumn IS evaluated (by eval).

<<GetColumnNames returns a list of the table's column names.  char() makes a string for concatenation.

dt = New Table( "Untitled",

  Add Rows( 1 ),

  New Column( "a", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [1] ) ),

  New Column( "b", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [2] ) ),

  New Column( "c", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [4] ) ),

  New Column( "d", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [8] ) ),

  New Column( "e", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [16] ) ),

  New Column( "f", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [32] ) )

);

cc = N col (dt);

names=dt<<getColumnNames;

For( i = 1, i <= cc, i = i + 2,

  Eval( // evaluate the expression returned by...

  Eval Expr( // evaluate the embedded expr...

  New Column( "Delta " || char(names[ i + 1 ]), // convert the column to a string

  numeric, continuous,

  // Formula won't evaluate on  its own.  Needs TWO expr for this case

  Formula( Expr( names[ i + 1 ] ) - Expr( names[ i ] ) )

  )

  )

  )

);

/* ----- resulting script -----------------

New Table( "Untitled",

  Add Rows( 1 ),

  New Column( "a", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [1] ) ),

  New Column( "b", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [2] ) ),

  New Column( "c", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [4] ) ),

  New Column( "d", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [8] ) ),

  New Column( "e", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [16] ) ),

  New Column( "f", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [32] ) ),

  New Column( "Delta b", Numeric, "Continuous", Format( "Best", 10 ), Formula( :p - :a ) ),

  New Column( "Delta d", Numeric, "Continuous", Format( "Best", 10 ), Formula( :d - :c ) ),

  New Column( "Delta f", Numeric, "Continuous", Format( "Best", 10 ), Formula( :f - :e ) )

)

*/

10929_pastedImage_5.png

Craige

View solution in original post

3 REPLIES 3
Craige_Hales
Super User

Re: Proper syntax to call Formula within Loop

this script might build something close to what you are after.  the Formula parameter to the New Column function needs a completely built formula, in the form it needs to be in when it actually runs, which is after your script runs.  the eval( evalexpr( ... expr(...) ... expr(...) ... ) ) strategy below is one way to do what you need.  expr() is used to tag the parts that need to be evaluated.  evalexpr() hunts them down and evaluates them.  eval() evaluates the expression returned by evalexpr.  Note the minus between the two expr() is NOT evaluated inside the for loop, but names[i+1] IS evaluated (by evalexpr) and NewColumn IS evaluated (by eval).

<<GetColumnNames returns a list of the table's column names.  char() makes a string for concatenation.

dt = New Table( "Untitled",

  Add Rows( 1 ),

  New Column( "a", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [1] ) ),

  New Column( "b", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [2] ) ),

  New Column( "c", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [4] ) ),

  New Column( "d", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [8] ) ),

  New Column( "e", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [16] ) ),

  New Column( "f", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [32] ) )

);

cc = N col (dt);

names=dt<<getColumnNames;

For( i = 1, i <= cc, i = i + 2,

  Eval( // evaluate the expression returned by...

  Eval Expr( // evaluate the embedded expr...

  New Column( "Delta " || char(names[ i + 1 ]), // convert the column to a string

  numeric, continuous,

  // Formula won't evaluate on  its own.  Needs TWO expr for this case

  Formula( Expr( names[ i + 1 ] ) - Expr( names[ i ] ) )

  )

  )

  )

);

/* ----- resulting script -----------------

New Table( "Untitled",

  Add Rows( 1 ),

  New Column( "a", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [1] ) ),

  New Column( "b", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [2] ) ),

  New Column( "c", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [4] ) ),

  New Column( "d", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [8] ) ),

  New Column( "e", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [16] ) ),

  New Column( "f", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [32] ) ),

  New Column( "Delta b", Numeric, "Continuous", Format( "Best", 10 ), Formula( :p - :a ) ),

  New Column( "Delta d", Numeric, "Continuous", Format( "Best", 10 ), Formula( :d - :c ) ),

  New Column( "Delta f", Numeric, "Continuous", Format( "Best", 10 ), Formula( :f - :e ) )

)

*/

10929_pastedImage_5.png

Craige
sornasst
Level III

Re: Proper syntax to call Formula within Loop

Hi Craig,

Thank you for sending me the correct code: I would not have been able to solve this by myself.

Regarding the use of "Eval" and "Eval Expr", why is it necessary to combine these two functions? Would "Eval Expr" alone do the trick?

Thank you for your help.

Sincerely,

Thierry

Craige_Hales
Super User

Re: Proper syntax to call Formula within Loop

EvalExpr doesn't perform the eval because you'd often want the expression so you could continue working on it.  In this case, there was nothing else to do.

evalexpr(3+4+expr(5+6))

3 + 4 + 11

JMP has powerful expression manipulation functions for performing surgery on expressions.  This is one example; arg, head, substituteinto are other functions that can work with expressions.

Introspection

Lists and Expressions

Craige