APL2 and J (2) - Indexing
Vector 13:2, page 137
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 137
This series of articles entitled APL and J will try to explain the J way of thinking, by contrasting APL and J coding examples. The term APL will be used generically to refer to facilities found in most commercial implementations of APL.
Here we look at how J handles indexing and indexed replacement.
Housekeeping¶
We use the letters V, M, and A for vectors, matrices and arrays of any dimension, optionally followed by numbers to denote their shape. Thus V for any vector, V5 for a vector of length 5, M45 for a 4-by-5 matrix, A245 for a 2-by-4-by-5 array. Where actual values are required, V5 will be defined as ⍳5, M45 as 4 5⍴⍳20, for example:
APL terminology will be used, except where J terminology is required for clarity. Since J uses origin 0 only, here ⎕io←0 is assumed throughout.
Indexing¶
In APL, you index variables using an indexing expression in brackets. Such expressions are not supported in J; instead, J uses a function { from. Compare the following expressions to select row 2 of a matrix:
M[2;] |
APL |
2{M |
J |
To understand this change, note that bracket indexing in APL does not conform to the rest of the APL language. Indexing is essentially a dyadic function taking arguments of the data and indices, yet the APL expression does not have the form of other APL dyadic functions (i.e. a function with arguments to the left and right).
Moreover you cannot use the APL expression as you would a normal function. For example if N is an enclosed array, each item of which is a matrix, you could not use bracket indexing to select row 2 of each item:
If you wanted to do this, you could define a cover function to index a matrix:
You could then select row 2 of M as:
and row 2 of each element of N as:
The corresponding J expressions are:
It may be seen that { is simply a functional form of bracket indexing. Because it is an ordinary function, you can use it in functional expressions, as in the example above. The idea of { is similar, but not identical, to the index function ⌷ in APL2.
Note that in the above example, should you wish to index row 2 of a 3D array, you would need to modify rowndx accordingly, but the J expression would remain unchanged.
Here are a couple more examples:
From Left Argument¶
The left argument can take various forms:
-
It can be one or more integers, which select corresponding items from the right argument. Negative integers select from the end, for example:
It is often convenient to apply rank with this form, for example:
-
The left argument can be one or more boxed lists, each element of which is a list of integers that select from corresponding axes:
This form allows scattered indexing:
-
The boxed lists in the left argument may themselves contain boxed lists, each element again selecting from corresponding axes:
Note that in J, this last form permits scattered indexing where each index may have a different number of elements. The following example has two indices: the first picks row 1, columns 3 and 4; the second picks row 2, column 3. The two results are assembled into a matrix, padding the second row with a fill of 0:
Selecting Entire Axis¶
In APL, when an axis is elided, the entire axis is selected. This is not the same as using an empty index:
In J, the elided axis is given by the boxed empty vector. Thus:
Here, it is convenient to use a: ace, which is the boxed empty vector:
In general, a boxed argument used as an index selects all but the indices given. So, the boxed empty means select all but the empty, i.e. select all. The following picks all but the first and last row from columns 2 and 3:
Indexed Replacement¶
As with indexing, indexed replacement in APL does not conform to the rest of the language. It requires three arguments – a set of indices, and two sets of data, at least one of which must be named. The named data item and the indices are given to the left of assignment, and the other data item to the right:
Indexed replacement is not a functional expression. The "result" of indexing is the values assigned (V in the above example), so that M is updated as a side effect.
In contrast, indexed replacement in J is an ordinary part of the language. It has two steps:
- the indices to be replaced are given as the argument to the adverb
}amend, returning a dyadic function that merges its two arguments according to the indices. - the function is then applied to the two data arguments. The elements of the left argument replace the elements of the right argument according to the indices.
For example, to replace row 2 of M with V:
The order of execution is shown by:
To replace row 2 of each item of a boxed list of matrices:
Note that indexed replacement in J does not require assignment and does not update the arguments, so there is no need for a named argument. The following updates M:
Arguments To Amend¶
The index arguments to } are symmetrical with index arguments to {. For example:
2{M45 select row 2
10 11 12 13 14
(100*i.5) 2} M45 amend row 2
0 1 2 3 4
5 6 7 8 9
0 100 200 300 400
15 16 17 18 19
(<1;1 2 3){M45 select row 1 columns 1 2 3
6 7 8
100 200 300 (<1;1 2 3)} M45 amend row 1 columns 1 2 3
0 1 2 3 4
5 100 200 300 9
10 11 12 13 14
15 16 17 18 19
Selective Assignment¶
Modern APLs can replace a portion of an array selected by an expression given to the left of assignment, this is called selective assignment. For example, the following replaces all occurrences of 2 in V by 20:
Similar facilities in J are provided by using a function argument to amend, which function is used to create the required indices. Thus:
bx 1 0 1 1 0 1 1 the utility bx returns indices of a boolean
0 2 3 5 6
f=. bx @ (2: =]) f returns indices where right argument is 2
20 f} 1 2 2 3 1 2 use f to replace 2 by 20
1 20 20 3 1 20
Fetch¶
A new function in J3.02 is {:: fetch which when used dyadically as in x fetch y returns the subarray of y according to the path x; the selection at each level is based on {, for example:
[A=. 1 2 3;4 5;i.4 5
┌─────┬───┬──────────────┐
│1 2 3│4 5│ 0 1 2 3 4│
│ │ │ 5 6 7 8 9│
│ │ │10 11 12 13 14│
│ │ │15 16 17 18 19│
└─────┴───┴──────────────┘
(2;_1 _1) fetch A fetch from item 2, the element in the last row
19 and column
(2;<2;2 3 4) fetch A fetch from item 2, the elements indexed by 2;2 3 4
12 13 14
This is similar to the reach facility of Dyalog APL, except that in J the final selection need not be a scalar:
Reference¶
Iverson, K.E. J Introduction and Dictionary, Iverson Software, 1996