Gregory Higley
Gregory Higley

Reputation: 16598

How can I define a verb in J that applies a different verb alternately to each atom in a list?

Imagine I've defined the following name in J:

m =: >: i. 2 4 5

This looks like the following:

 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 32 33 34 35
36 37 38 39 40

I want to create a monadic verb of rank 1 that applies to each list in this list of lists. It will double (+:) or add 1 (>:) to each alternate item in the list. If we were to apply this verb to the first row, we'd get 2 3 6 5 10.

It's fairly easy to get a list of booleans which alternate with each item, e.g., 0 1 $~{:$ m gives us 0 1 0 1 0. I thought, aha! I'll use something like +:`>: @. followed by some expression, but I could never quite get it to work.

Any suggestions?

UPDATE

The following appears to work, but perhaps it can be refactored into something more elegant by a J pro.

poop =: monad define
    (($ y) $ 0 1 $~{:$ y) ((]+:)`(]>:) @. [)"0 y
)

Upvotes: 2

Views: 293

Answers (4)

Cameron Chandoke
Cameron Chandoke

Reputation: 11

Function +:`>:"0"1

   1:`2:"0"1  >:i.2 4 5
1 2 1 2 1
1 2 1 2 1
1 2 1 2 1
1 2 1 2 1

1 2 1 2 1
1 2 1 2 1
1 2 1 2 1
1 2 1 2 1

Here the constant verbs 1: and 2: are used for clear demonstration, but substitute with your verbs of choice. The outer rank application "1 says to apply our verb to each row; the inner rank application ("0) says to alternate among 0-cells (atoms) since its operand is a cyclic gerund.

Explanation of ,@(+:`>:/."1)

Regarding ,@(+:`>:/."1) (from someone else's answer) preserving the original shape, this is because u@v is defined as (u@:v)"v. In this case v=.+:`>:/."1, so its rank is 1 (a shorthand for 1 1 1). So ,@v,@:v"v,@:v"1(,@:v)"1. This means that v will be applied separately on each row, and each v-result individually will be raveled by ,. In our case, each iteration of v on a row produces a [5 1] matrix since f/. produces a singleton list for each element of each row (generally the diagonals, but those of a row are its individual elements). , then ravels that matrix into a row; thus, the shape remains unchanged.

The first trailing 1 in the [2 4 5 1 1] shape that obtains from [: $ ,"0@(+:`>:/.)"1 is due to the (…)"1-results—each of shape [5 1]—being framed by 2 4, i.e., the frame with respect to the 1-cells (c.f. https://code.jsoftware.com/wiki/Vocabulary/FramingFill#Argument_Frame_And_Result_Frame). The latter trailing 1 is due to ,"0 ravelling each atom into a singleton vector.

Upvotes: 1

rdm
rdm

Reputation: 688

(,@(+:`>:/.)"1 a) works, but note that ((* 2 1 $~ $)@(+ 0 1 $~ $)"1 a) would also have worked (and is about 20 times faster, on large arrays, in my brief tests).

Upvotes: 1

Nick
Nick

Reputation: 199

I spent a long time and I looked at it, and I believe that I know why ,@ works to recover the shape of the argument.

The shape of the arguments to the parenthesized phrase is the shape of the argument passed to it on the right, even though the rank is altered by the " conjugate (well, that is what trace called it, I thought it was an adverb). If , were monadic, it would be a ravel, and the result would be a vector or at least of a lower rank than the input, based on adverbs to ravel. That is what happens if you take the conjunction out - you get a vector.

So what I believe is happening is that the conjunction is making , act like a dyadic , which is called an append. The append alters what it is appending to what it is appending to. It is appending to nothing but that thing still has a shape, and so it ends up altering the intermediate vector back to the shape of the input.

Now I'm probably wrong. But $,"0@(+:>:/.)"1 >: i. 2 4 5 -> 2 4 5 1 1` which I thought sort of proved my case.

Upvotes: 1

David
David

Reputation: 7153

I would use the oblique verb, with rank 1 (/."1)- so it applies to successive elements of each list in turn.

You can pass a gerund into /. and it applies them in order, extending cyclically.

   +:`>: /."1 m 
 2
 3
 6
 5
10

12
 8
16
10
20

22
13
26
15
30

32
18
36
20
40


42
23
46
25
50

52
28
56
30
60

62
33
66
35
70

72
38
76
40
80

Upvotes: 3

Related Questions