Search code examples
j

Generate data following specified pattern in J


I'm dabbling my feet with J and, to get the ball rolling, decided to write a function that:

  • gets integer N;
  • spits out a table that follows this pattern:

(example for N = 4)

1
0 1
0 0 1
0 0 0 1

i.e. in each row number of zeroes increases from 0 up to N - 1.

However, being newbie, I'm stuck. My current labored (and incorrect) solution for N = 4 case looks like:

   (4 # ,: 0 1) #~/"1 1 (1 ,.~/ i.4)
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

And the problem with it is twofold:

  • it's not general enough and looks kinda ugly (parens and " usage);
  • trailing zeroes - as I understand, all arrays in J are homogeneous, so in my case every row should be boxed.

Like that:

┌───────┐
│1      │
├───────┤
│0 1    │
├───────┤
│0 0 1  │
├───────┤
│0 0 0 1│
└───────┘

Or I should use strings (e.g. '0 0 1') which will be padded with spaces instead of zeroes.

So, what I'm kindly asking here is:

  • please provide an idiomatic J solution for this task with explanation;
  • criticize my attempt and point out how it could be finished.

Thanks in advance!


Solution

  • Like so many challenges in J, sometimes it is better to keep your focus on your result and find a different way to get there. In this case, what your initial approach is doing is creating an identity matrix. I would use

       =/~@:i. 4
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
    

    You have correctly identified the issue with the trailing 0's and the fact that J will pad out with 0's to avoid ragged arrays. Boxing avoids this padding since each row is self contained.

    So create your lists first. I would use overtake to get the extra 0's

       4{.1
    1 0 0 0
    

    The next line uses 1: to return 1 as a verb and boxes the overtakes from 1 to 4

       (>:@:i. <@:{."0 1:) 4
    +-+---+-----+-------+
    |1|1 0|1 0 0|1 0 0 0|
    +-+---+-----+-------+
    

    Since we want this as reversed and then made into strings, we add ":@:|.@: to the process.

       (>:@:i.  <@:":@:|.@:{."0 1:) 4
    +-+---+-----+-------+
    |1|0 1|0 0 1|0 0 0 1|
    +-+---+-----+-------+
    

    Then we unbox

       >@:(>:@:i.  <@:":@:|.@:{."0 1:) 4
    1      
    0 1    
    0 0 1  
    0 0 0 1
    

    I am not sure this is the way everyone would solve the problem, but it works.

    An alternative solution that does not use boxing and uses the dyadic j. (Complex) and the fact that

       1j4 # 1
    1 0 0 0 0
       (1 j. 4) # 1
    1 0 0 0 0
       (1 #~ 1 j. ]) 4
    1 0 0 0 0
    

    So, I create a list for each integer in i. 4, then reverse them and make them into strings. Since they are now strings, the extra padding is done with blanks.

       (1 ":@:|.@:#~ 1 j. ])"0@:i. 4
    1      
    0 1    
    0 0 1  
    0 0 0 1
    

    Taking this step by step as to hopefully explain a little better.

       i.4
    0 1 2 3
    

    Which is then applied to (1 ":@:|.@:#~ 1 j. ]) an atom at a time, hence the use of "0 Breaking down what is going on within the parenthesis. I first take the right three verbs which form a fork.

       ( 1 j. ])"0@:i.4
    1 1j1 1j2 1j3
    

    Now, effectively that gives me

    1 ":@:|.@:#~ 1 1j1 1j2 1j3
    

    The middle tine of the fork becomes the verb acting on the two noun arguments.The ~ swaps the arguments. so it becomes equivalent to

    1 1j1 1j2 1j3 ":@:|.@:# 1
    

    which because of the way @: works is the same as

    ": |. 1 1j1 1j2 1j3 # 1
    

    I haven't shown the results of these components because using the "0 on the fork changes how the arguments that are sent to the middle tine and assembled later. I'm hoping that there is enough here that with some hand waving the explanation may suffice

    The jump from tacit to explicit can be a big one, so it may be a better exercise to write the same verb explicitly to see if it makes more sense.

       lowerTriangle =: 3 : 0
    ​rightArg=. i. y
    ​complexCopy=. 1 j. rightArg
    ​1 (":@:|.@:#~)"0 complexCopy
    ​)
       lowerTriangle 4
    1      
    0 1    
    0 0 1  
    0 0 0 1
       lowerTriangle 5
    1        
    0 1      
    0 0 1    
    0 0 0 1  
    0 0 0 0 1
    

    See what happens when you 'get the ball rolling'? I guess the thing about J is that the ball goes down a pretty steep slope no matter where you begin. Exciting, eh?