Vocabulary/Idioms
Common Idioms used in J best practice
Sometimes the right way to do a job in J isn't obvious. Here's a collection of useful tricks.
The Empty List and the Void Argument
(5 oranges) is not the same as (5 lemons) – everyone agrees.
But what about (0 oranges) and (0 lemons)? Most people would accept that these two sets are indeed the same.
J has a builtin notion of the empty set – or rather the empty list. J treats the many phrases that compute the empty list as identical (-:)
'' -: i.0 1 '' -: 0$0 1 '' -: 0$a: 1
You often see these expressions for the empty list in code written by J experts
'' i.0 0$0 $0
The first idiom (called quote-quote) is the most popular, because it is a constant. Not a phrase which needs to be evaluated.
You also see quote-quote frequently used as the Void Argument in a verb call, i.e. where the argument value is
- not valid or not appropriate within this call
- not used in the body of the verb
- to be substituted by a built-in default list.
But if you mean: "y is a list of numbers, which in this call just happens to be empty" then hint at your intention by using (0$0) or (i.0)
6!:0'' 2017 6 8 2 56 11.0916 NB. 6!:0 accepts a format string, but here we ask for the default format exit'' NB. executing a verb: the y-argument is mandatory but verb makes no use of it
If you are building a table t row-by-row
t=: i.0 0 NB. create t like this t=: '' NB. not like this: it won't work correctly
The standard library (stdlib.ijs) creates in the z-locale these variants of the empty list
EMPTY=: i.0 0 empty=: EMPTY"_
Another use for the empty list is to safely terminate an explicit definition in which a verb has been assigned. This avoids seeing the error message
|noun result was required: yourVerb
Example
settrace=: verb define if. TRACE do. smoutput=: 0 0 $ 1!:2&2 else. smoutput=: ] end. EMPTY NB. avoids error message: |noun result was required )
Variable-Length Records
To split a list into fields, assuming each field starts with a number giving its length:
1. For each position in y compute where the next record would start (assuming a record starts at that position)
2. Work through the chain of records using the special combination: {~^:a:
data =. '5There2is1a4tide2in3the7affairs2of3men' NB. 1-digit length separates words ]l =. >: (a. i. data) - a. i. '0' NB. Each start-of-record has a length. Others immaterial 6 37 57 54 67 54 3 58 68 2 50 5 69 58 53 54 3 ... ]n =. (#l) <. l + i. # l NB. Now each position of n has a next-record position 6 38 38 38 38 38 9 38 38 11 ... ]pos =. (n,_1) {~^:a: 0 NB. find all the record starting positions, and return them as an array 0 6 9 11 16 19 23 31 34 38 _1 ((i. #data) e. pos) <;._1 data NB. Extract the valid fields into boxes +-----+--+-+----+--+---+-------+--+---+ |There|is|a|tide|in|the|affairs|of|men| +-----+--+-+----+--+---+-------+--+---+
Extract The Diagonal Of A Table
To extract the principal diagonal of a table, use: (<0 1) |: y
]a =: 4 4 $ 'abcdefghijklmnop' abcd efgh ijkl mnop (<0 1) |: a NB. The main diagonal afkp (<0 1) |: i. 4 5 NB. For non-square arrays, it's the diagonal starting at the top-left 0 6 12 18
The x-argument of Rearrange Axes (|:) specifies the axes to retain
- each box corresponding to one result axis
- multiple axes in a box run together to make a single axis taken along a diagonal.
The method generalizes to higher-dimensional arrays.
Polynomial Multiplication
pmul =: +//.@(*/) 1 2 pmul 3 4 2 NB. (1+2x)(3+4x+2x^2)=3+10x+10x^2+4x^3 3 10 10 4
Ordinal Number
The ordinal number of an item of an array is the index the item would have if the array were sorted. The first item is ordinal 0, etc. Applying /:@/: y calculates the ordinal numbers. Note that /:@/: y performes better than /: /: y because it is a Special Combination.
/:@/: 3 1 4 1 5 9 2 0 3 1 4 5
Ordinal numbers can be used to unsort an array, i.e. put a sorted array back into its original order. For example, suppose we want to modify a vector of integers so that duplicate values differ slightly from each other.
nn=. 3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 /:~nn NB. Sort 1 1 2 3 3 4 5 5 5 6 7 8 9 9 9 </.~/:~nn NB. Box unique values +---+-+---+-+-----+-+-+-+-----+ |1 1|2|3 3|4|5 5 5|6|7|8|9 9 9| +---+-+---+-+-----+-+-+-+-----+
Now, add a small amount to each duplicate:
0.01 (] + [ * [: i. [: # ]) &.> </.~/:~nn +------+-+------+-+-----------+-+-+-+-----------+ |1 1.01|2|3 3.01|4|5 5.01 5.02|6|7|8|9 9.01 9.02| +------+-+------+-+-----------+-+-+-+-----------+ ;0.01(] + [ * [: i. [: # ])&.></.~/:~nn NB. Raze to remove boxes 1 1.01 2 3 3.01 4 5 5.01 5.02 6 7 8 9 9.01 9.02
Finally, use ordinal numbers to put the modified numbers back into their original order.
(/:@/:nn) { ; 0.01 (] + [ * [: i. [: # ]) &.> </.~/:~nn 3 1 4 1.01 5 9 2 6 5.01 3.01 5.02 8 9.01 7 9.02
The final result tags each duplicate item by 0.01 times the number of duplicates preceding it.
String Searching
Forms For String Searches Action Preferred Form Find Matching Positions x I.@:E. y Count Matching Positions x +/@:E. y Is Substring x in y? x +./@:E. y
str=. 'How now brown cow?' 'ow' I.@:E. str NB. Starting positions of 'ow' 1 5 10 15 'ow' +/@:E. str NB. Number of occurrences of 'ow' 4 'how' +./@:E. str NB. Is 'how' in string? 0 'How' +./@:E. str NB. Is 'How' in string? 1
Array Coordinates ("Index of" for a rank 2+ array)
Forms For Array Coordinates Action Preferred Form Find ones in a boolean array ($ #: I.@,) y Find first by predicate p ($ #: (i. p)@,) y Find all by predicate p ($ #: (I.@:= p)@,) y
]arr =. 100 ?~ 8 $ 8 44 49 36 11 77 61 92 42 87 19 31 7 75 45 27 18 64 99 18 92 75 49 71 97 75 48 77 41 33 36 13 80 20 2 74 26 66 99 72 64 75 48 46 70 23 87 92 98 54 19 3 7 85 95 20 52 8 35 79 5 95 85 18 67 ]coords =. ($ #: I.@,) 77= arr NB. Coordinates of all 77s 0 4 3 2 _ coords} arr NB. Example use of coords (assign _ to them) 44 49 36 11 _ 61 92 42 87 19 31 7 75 45 27 18 64 99 18 92 75 49 71 97 75 48 _ 41 33 36 13 80 20 2 74 26 66 99 72 64 75 48 46 70 23 87 92 98 54 19 3 7 85 95 20 52 8 35 79 5 95 85 18 67 ($ #: (i. <./)@,) arr NB. argmin (p is <./) 4 1 NB. this is the 2 at row 4, col 1 ($ #: (I.@:= >./)@,) arr NB. argmax (get every coordinate) 2 1 4 5
It is also quite concise (though slower) to zero out all the unwanted values in the array, and apply 4$. $. (get indices of the sparse array) to get all the nonzero indices. Referenced from [1].
Split array into N sized chunks
_5 ]\ 'abcdefghijklmnopqrstuvwxyz' abcde fghij klmno pqrst uvwxy z _6 ]\ i.32 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 0 0 0
---