A問題從安德瓦關於列公式開始了這篇文章。 如果您僅使用公式編輯器建立列公式,則幾乎可以忽略所有這些。 這篇文章是關於使用 JSL 建立列公式。
首先,簡單介紹一下 Formula 指令。 這是一個非常簡單的:
The formula for column C adds columns A and BThe formula for column C adds columns A and BThe formula for column C adds columns A and BThe formula for column C adds columns A and BC 列的公式將 A 列和 B 列相加
表腳本(左上角三角形 -> 複製表腳本,貼上到編輯器中)如下所示:
New Table( "abc", Add Rows( 2 ),
New Column( "a", Numeric, "Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( :a + :p</img> )
)
)
第5行設定公式;此公式是將 a 列和 b 列相加的表達式。 該表達式直到很久以後才會運行。 此表達式作為表達式保存為列的一部分。 如果將另一行新增至表格或如果 a 或 b 列中的值發生更改,則可以再次計算表達式以獲得 c 列的值。
這是既友善又不尋常的行為。 不尋常的是,因為大多數函數都會評估其參數:sqrt( 4 + 5 ) 傳回 3。 友好,因為您幾乎不會希望 JMP 在將列的公式分配給列之前對其求值。
有時公式表達式可能非常複雜。 如此複雜,編寫一個程式來編寫表達式會更容易。 要在公式命令中執行此操作,您需要一種方法來告訴公式命令預先計算參數並將結果表達式用作公式。 您可以透過在程式碼周圍添加 eval() 包裝器來進行預先評估。 當公式命令看到“eval”包裹在表達式中時,它就會運行程式碼並使用結果。
lookup = function({t,u}, expr(a+b) );
New Table( "abc",
Add Rows( 2 ),
New Column( "a",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( eval( lookup(1,2) ) )
)
)
使用者定義的「查找」函數(第 1 行)不是很聰明,但必須執行它才能檢索 expr(a+b) 作為傳回值。 在第 7 行,eval() 包裝器表示列公式不會設定為“lookup(1,2)”,而是設定為 Lookup(1,2) 傳回的表達式。與先前相同的表,具有相同的列公式。
如果您希望將列公式設定為以 eval( ) 開頭的表達式該怎麼辦?既然從 eval() 開始意味著評估參數並使用結果,那麼 Formula 指令怎麼能做到這一點呢? (我很難想出一個有趣的例子,但是多發性硬化症問題的答案中有一個。)答案是 Name Expr( )。 Name Expr 是一個 JSL 函數,通常用於從 JSL 變數中取得表達式而不對其求值。 作為公式命令中最外層的包裝器,它只會傳回參數而不對其求值。 第一個範例可以使用它,除了這個解釋之外沒有什麼充分的理由,就像這樣,返回完全相同的表:
New Table( "abc", Add Rows( 2 ),
New Column( "a", Numeric, "Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( Name Expr( :a + :p</img> ) )
)
)
但對於多發性硬化症例如,它是必需的,因為 eval 的巧妙使用(這可能需要另一篇部落格文章來解釋它的作用)。 這是原始問題的最終表格。 我將自己的想法加入為第二個公式列。
New Table( "final?",Add Rows( 9 ),
New Column( "color",Character,"Nominal",
Set Values({"green", "green", "blue", "yellow", "red", "red", "yellow", "green", "green"})),
New Column( "count",Numeric,"Continuous",Format( "Best", 12 ),
Formula( Name Expr( Eval( Eval Expr( Col Sum( Row() <= Expr( Row() ), :color ) ) ) ) )),
New Column( "another count",Numeric,"Continuous",Format( "Best", 12 ),
Formula(
n = 0;
For( i = 1, i <= Row(), i++,
If( :color == :color[i], n++ )
);
n;
)
)
);
第三列的公式可以更快,但會犧牲清晰度,方法是向後查找最後一個匹配項並在該計數上加一。 清晰度與效率是一種權衡。

因此,我要修復在此過程中發現的錯誤:當資料表建立腳本來重現自身時(如上面的範例),它也必須產生 JSL 來重現列公式。 如果列公式以特殊的 eval( ) 包裝器開頭,且 eval 應該是公式的一部分,則 JMP 需要新增名稱表達式。
2018 年 4 月 21 日更新:修復上一篇部落格的自動轉換。