Publication date: 04/12/2021

Indexing into a matrix (or a list) with another matrix (or list) is a powerful technique for making scripts fast and small. JMP 13 and later handles one edge case differently.

Consider the following example of using a matrix as an index into a data column.

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

tall rows = Loc( :height << Get Values() >= 67 ); // [25, 27, 30, 37, 39, 40]

`:height[tall rows]; // [68, 69, 67, 68, 68, 70]`

N Rows( :height[tall rows] ); // 6

The second line is the key. :height << Get Values() returns the values of the height column as a matrix. The comparison >= 67 returns a matrix of 0s and 1s corresponding to where the expression is false (0) or true (1). The Loc() function returns the locations of the 1s within the previous matrix.

In this case, you get [25, 27, 30, 37, 39, 40] as the row numbers where the height column is greater than or equal to 67. That's pretty handy by itself, but the real power comes from being able to use that matrix as the index into a column or other matrix as in the third and fourth lines.

The alternative to this technique is to write a For() loop to iterate through every row explicitly. JMP still loops through the rows in either case, but the looping is much faster if done internally rather than in JSL. And the JSL is more compact without the explicit loop.

You can do the same thing with a matrix variable instead of a data column reference:

`m = :height << 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

Consider the same examples with a different height cutoff (70 instead of 67):

tall rows = Loc( :height << Get Values() >= 70 ); // [40]

`:height[tall rows]; // [70]`

N Rows( :height[tall rows] ); // 1

`m = :height << Get Values();`

tall rows = Loc( m >= 70 ); // [40]

`m[tall rows]; // [70]`

N Rows( m[tall rows] ); /* error in JMP 12 and prior versions

`otherwise, returns 1 */`

Notice that m[tall rows] returned 70 instead of [70]. In many cases, a 1x1 matrix and a number are treated the same way, but not always. The N Rows() function is one example where it makes a difference. The indexing is too aggressively simplifying the 1x1 matrix into a number.

One work-around is to call Is Matrix() before using N Rows(). An alternative is to concatenate an empty matrix to the result, which creates a matrix whether the source is a number or a matrix:

m = m |/ []

In JMP 13 and later, the 1x1 matrix is maintained so that the result of the index operation is a matrix whenever the index itself is a matrix. The same principle applies to list indexing. Data table column indexing has always followed this principle.

Want more information? Have questions? Get answers in the JMP User Community (community.jmp.com).