Vocabulary/Idioms

From J Wiki
Jump to: navigation, search

Back to: Vocabulary

Idioms

Sometimes the right way to do a job in J isn't obvious. Here is 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…

   '' -: i.0
1
   '' -: 0$0
1
   '' -: 0$a:
1

You often see these idioms for the empty list used in J code written by experts:

''
i.0
0$0

Of these, the first (quote-quote) is the most popular, because it is a noun constant, not a phrase.

You also see quote-quote used a lot as the void argument, i.e. wherever an argument value is…

  • not valid or inappropriate for this invocation
  • not used in the body of the verb
  • to be replaced by a builtin default list.

But if you mean "here is a list of numbers, which on this occasion just happens to be empty" then it's good to signal your intention by using (0$0) or (i.0).

Examples:

   6!:0''
2017 6 8 2 56 11.0916
   NB. 6!:0 accepts a format string, but here we just want the default format

exit''
   NB. a J verb always needs a y-argument, but exit makes no use of it.

If you are building a table row by row, quote-quote will not work correctly. Instead (i.0 0) is conventional to use.

The standard library (stdlib.ijs) defines the words:

EMPTY=: i.0 0
empty=: EMPTY"_

Another use for EMPTY, empty or (i.0 0) is to end an explicit definition safely whenever verbs have been assigned. This avoids a perplexing syntax error -- see: Vocabulary/ErrorMessages#syntaxresult.

settrace=: verb define
if. -.TRACE do. 
  smoutput=: ]
else.
  smoutput=: 0 0 $ 1!:2&2
end.
empty''   NB. --or: EMPTY
)

Variable-Length Records

You need to split a list into fields where each field starts with a length.

First you calculate, for each position in y, where the next record would start if a record starts at that position. The you use the special sequence {~^:a: to go through the chain of records.

   data =. '5There2is1a4tide2in3the7affairs2of3men'  NB. 1-byte numeric length betwenen 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 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 method generalizes to higher-dimensional arrays. The x argument to x |: y specifies the axes to retain, with each box corresponding to one result axis, and with multiple axes in a box run together to make a single axis taken along a diagonal.


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.

   /: /: 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