Vocabulary/Idioms

From J Wiki
Jump to navigation Jump to search

Back to: Vocabulary

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

---