別の行列(またはリスト)を使った行列(またはリスト)のインデックス化は、スクリプトを高速にし、また記述を短くする上でとても便利な手法です。JMP 13以降では、あるエッジケースの扱いが以前のバージョンと異なります。
ある行列をデータ列のインデックスとして使用する以下の例を見てみましょう。
dt = Open( "$SAMPLE_DATA/Big Class.jmp" );
tall rows = Loc( :Name("身長(インチ)") << Get Values() >= 67 ); // [25, 27, 30, 37, 39, 40]
:Name("身長(インチ)")[tall rows]; // [68, 69, 67, 68, 68, 70]
N Rows( :Name("身長(インチ)")[tall rows] ); // 6
ここで重要なのは2行目です。:Name("身長(インチ)") << Get Values()は「身長(インチ)」列の値を行列として戻します。比較の>= 67は、式が偽(0)または真(1)のどちらであるかに対応した、0と1の行列を戻します。Loc()関数は前の行列内における1の場所を戻します。
この例では、「身長(インチ)」列が67以上である行番号として[25, 27, 30, 37, 39, 40]が得られます。この結果だけでも十分に便利なのですが、この例の重要なポイントは3行目と4行目にあります。ご覧のとおり、得られた行列を列または別の行列のインデックスとして用いることが可能です。
この手法の別の方法として、For()ループを書いてすべての行を明示的に反復することもできます。どちらの手法でもJMPは行をループしますが、JSLを使わずに内部で演算を行う場合には、ループを使う手法の方がかなり高速です。ただし、JSLの方が明示的なループを使わないため、簡潔に記述できます。
データ列参照の代わりに行列変数を使っても同じことが行えます。
m = :Name("身長(インチ)") << Get Values();
tall rows = Loc( m >= 67 ); // [25, 27, 30, 37, 39, 40]
m[tall rows]; // [68, 69, 67, 68, 68, 70]
N Rows( m[tall rows] ); // 6
同じ例で、今度は身長の基準を変えてみましょう(67の代わりに70)。
tall rows = Loc( :Name("身長(インチ)") << Get Values() >= 70 ); // [40]
:Name("身長(インチ)")[tall rows]; // [70]
N Rows( :Name("身長(インチ)")[tall rows] ); // 1
m = :Name("身長(インチ)") << Get Values();
tall rows = Loc( m >= 70 ); // [40]
m[tall rows]; // [70]
N Rows( m[tall rows] ); /* JMP12以前のバージョンではエラー
それ以外は1を戻す */
以前は、m[tall rows]は[70]ではなく70 を戻していました。多くの場合、1x1行列と数値は同じように扱われますが、必ずしも同じというわけではありません。その一例としてN Rows()関数が挙げられます。インデックス化で1x1行列が1つの数値に簡素化されるとこのようなことが起こり得ます。
N Rows()を使用する前にIs Matrix()を呼び出す方法が対応策の1つです。別の方法として、空の行列を結果に連結することもできます。そうすれば、ソースが数値と行列のどちらであっても行列が作成されます。
m = m |/ []
JMP 13以降では1x1行列が維持されるため、インデックス自体が行列であれば、インデックス演算の結果は行列になります。リストのインデックス化にも同じ原理が適用されます。データテーブル列のインデックス化は以前からこの原理に従っていました。