How do I negate a selector in J lang? - j

I am playing with selection. Let's look at the initial example:
rarg=. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
_1 (<(<0 1),(<0 1)) } ( 4 4 $ rarg)
_1 _1 2 3
_1 _1 6 7
8 9 10 11
12 13 14 15
Here I want to overwrite block {rows=0,1; columns=0,1}. I can use instead of -1 the block :
(2 2 $ _1 _2 _3 _4) (<(<0 1),(<0 1)) } ( 4 4 $ rarg)
_1 _2 2 3
_3 _4 6 7
8 9 10 11
12 13 14 15
If I negate rows and columns choice in selector I end-up with the expected:
_1 (<(<<0 1),(<<0 1)) } ( 4 4 $ rarg)
0 1 2 3
4 5 6 7
8 9 _1 _1
12 13 _1 _1
So far so good. But let's assume I want to "negate" the selector (<(<0 1),(<0 1)) and have something like this:
_1 NEGATED_SEL } ( 4 4 $ rarg)
0 1 _1 _1
4 5 _1 _1
_1 _1 _1 _1
_1 _1 _1 _1
Is there a way to achieve that using the above selector?
If yes, what if I would like to specify not -1 but arbitrary values?
Thanks a lot in advance!

The "correct" way would be using exclude (<):
(<< 0 1) { i. 4 4
0 1 2 3
4 5 6 7
(<<< 0 1) { i. 4 4
8 9 10 11
12 13 14 15
But, as #Dan_Bron mentioned, this is not permitted by } as the selection would not be rectangular.
You can still use exclude if you first unravel and then re-ravel your input.
sel =: <(<<0 1),(<<0 1)
r =: i. 4 4
sel { r
10 11
14 15
_1 sel } r
0 1 2 3
4 5 6 7
8 9 _1 _1
12 13 _1 _1
new =: -i. 12
($r) $ new (<<<,sel { r) } ,r
0 _1 _2 _3
_4 _5 _6 _7
_8 _9 10 11
_10 _11 14 15
For a general input m, you could convert the selection to indices by sel { i. $m:
($m) $ new (<<<,sel { i.$m) } , m

A standard way is using a Composite Item (m}) as Dan Bron said:
aNEGATED_SEL1=. 1 : 'y=. (*./~ 1 < i. # y)} y ,: m' NB. adverb, 1st variant
aNEGATED_SEL2=. 1 : 'y=. (*:/~ 1 < i. # y)} m ,: y' NB. adverb, 2nd variant
_1 aNEGATED_SEL1 ( 4 4 $ rarg)
0 1 2 3
4 5 6 7
8 9 _1 _1
12 13 _1 _1
_1 aNEGATED_SEL2 ( 4 4 $ rarg)
0 1 2 3
4 5 6 7
8 9 _1 _1
12 13 _1 _1
If an overwrite block must vary, it might be supplied as a parameter to a conjunction:
cNEGATED_SEL=. 2 : 'y=. (*./~ n <: i. # y)} y ,: m'
_1 cNEGATED_SEL 2 ( 4 4 $ rarg)
0 1 2 3
4 5 6 7
8 9 _1 _1
12 13 _1 _1
_1 cNEGATED_SEL 3 ( 6 6 $ rarg)
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 0 1
2 3 4 _1 _1 _1
8 9 10 _1 _1 _1
14 15 0 _1 _1 _1
The form used above (Noun Modifier) forced to incapsulate an adverb (}). A recent J Engine modifications (since J903 beta-r) may allow a form you requested (Noun Modifier }).

Thanks everybody for great hints and answers. The final solution with intermediate steps (for beginner J enthusiasts like myself) to follow
Initial matrix
r =: 100 + 5 5 $ i.25
r
100 101 102 103 104
105 106 107 108 109
110 111 112 113 114
115 116 117 118 119
120 121 122 123 124
Selection - we want to update everything besides what selects
sel =: <(<1 2),(<1 2)
sel { r
106 107
111 112
Indices the selection affects:
,sel { i.$r
6 7 11 12
Indices the selection omits:
selIxs =: (< (<< (,sel { i.$r)) ) { ,i.$r
0 1 2 3 4 5 8 9 10 13 14 15 16 17 18 19 20 21 22 23 24
Final update (we are flattening the matrix to be updated, use vector like updating (here with -1 elements and previously picked ixs) using } and finally enforce shape of the initial matrix)
($r) $ _1 selIxs } ,r
_1 _1 _1 _1 _1
_1 106 107 _1 _1
_1 111 112 _1 _1
_1 _1 _1 _1 _1
_1 _1 _1 _1 _1

Related

How to drop columns of csv data in J

I have a lot of csv files that I have to drop the date column.
I have a J line that reads in csv file into a numeric array, rdtabfile =: (0&".;.2#:(TAB&,)#:}:);._2) # ReadFile #<
If you know the column number of the date column, I would just use a mask across each line of the array and the copy # dyadic verb.
[ t =: i. 4 5
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
mask=: ~: [: i. # NB. x would be the column to be dropped, y is the numeric matrix
delcol=: (mask # ])"1
1 delcol t
0 2 3 4
5 7 8 9
10 12 13 14
15 17 18 19
delcola=: ((~: [: i. #) # ])"1 NB. can be done in one line
2 delcola t
0 1 3 4
5 6 8 9
10 11 13 14
15 16 18 19

Print values and it's associated index when working with vectors / matrix in J

If I want to check how many values in a vector or matrix are less than a given value
I can use +/ (a < 20). But what if I wanted to know both the specific value and it's index.
Something like (2(value) 5(index)) as a table. I looked at i., i: (which give first and last position) and I. Does sorting first help?
A very common pattern in J is the creation of a mask from a filter and applying an action on and/or using the masked data in a hook or fork:
((actions) (filter)) (data)
For example:
NB. Random array
a =: ? 20 $ 10
6 3 9 0 3 3 0 6 2 9 2 4 6 8 7 4 6 1 7 1
NB. Filter and mask
f =: 5 < ]
m =: f a
1 0 1 0 0 0 0 1 0 1 0 0 1 1 1 0 1 0 1 0
NB. Values of a on m
m # a
6 9 6 9 6 8 7 6 7
NB. Indices of a on m
I. m
0 2 7 9 12 13 14 16 18
NB. Joint results
(I.m) ,: (m # a)
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7
In other words, in this case you have m&# and f acting on a and I. acting on m. Notice that the final result can be derived from an action on m alone by commuting the arguments of copy #~:
(I. ,: (a #~ ]) m
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7
and a can be pulled out from the action on m like so:
a ( (]I.) ,: (#~ ])) m
But since m itself is derived from an action (f) on a, we can write:
a ( (]I.) ,: (#~ ])) (f a)
which is a simple monadic hook y v (f y) → (v f) y.
Therefore:
action =: (]I.) ,: (#~ ])
filter =: 5 < ]
data =: a
(action filter) data
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7

Use # (Copy) as selection or filter on 2-d array

The J primitive Copy (#) can be used as a filter function, such as
k =: i.8
(k>3) # k
4 5 6 7
That's essentially
0 0 0 0 1 1 1 1 # i.8
The question is if the right-hand side of # is 2-d or higher rank shaped array, how to make a selection using #, if possible. For example:
k =: 2 4 $ i.8
(k > 3) # k
I got length error
What is the right way to make such a selection?
You can use the appropriate verb rank to get something like a 2d-selection:
(2 | k) #"1 1 k
1 3
5 7
but the requested axes have to be filled with 0s (or !.) to keep the correct shape:
(k > 3) #("1 1) k
0 0 0 0
4 5 6 7
(k > 2) #("1 1) k
3 0 0 0
4 5 6 7
You have to better define select for dimensions > 1 because now you have a structure. How do you discard values? Do you keep empty "cells"? Do you replace with 0s? Is structure important for the result?
If, for example, you only need the "values where" then just ravel , the array:
(,k > 2) # ,k
3 4 5 6 7
If you need to "replace where", then you can use amend }:
u =: 5 :'I. , 5 > y' NB. indices where 5 > y
0 u } k
0 0 0 0
0 5 6 7
z =: 3 2 4 $ i.25
u =: 4 :'I. , (5 > y) +. (0 = 3|y)' NB. indices where 5>y or 3 divides y
_999 u } z
_999 _999 _999 _999
_999 5 _999 7
8 _999 10 11
_999 13 14 _999
16 17 _999 19
20 _999 22 23

Avoiding a repeated verb name in a train

Consider a dyadic verb g, defined in terms of a dyadic verb f:
g=. [ f&.|: f
Is it possible to rewrite g so that the f term appears only once, but the behavior is unchanged?
UPDATE: Local Context
This question came up as part of my solution to this problem, which "expanding" a matrix in both directions like so:
Original Matrix
1 2 3
4 5 6
7 8 9
Expanded Matrix
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
4 4 4 4 5 6 6 6 6
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
My solution was to expand the matrix rows first using:
f=. ([ # ,:#{.#]) , ] , [ # ,:#{:#]
And then to apply that same solution under the transpose to expand the columns of the already row-expanded matrix:
3 ([ f&.|: f) m
And I noticed that it wasn't possible to write my solution with making the temporary verb f, or repeating its definition inline...
Try it online!
Knowing the context helps. You can also approach this using (|:#f)^:(+: x) y. A tacit (and golfed) solution would be 0&(|:{.,],{:)~+:.
(>: i. 3 3) (0&(|:{.,],{:)~+:) 2
1 1 1 2 3 3 3
1 1 1 2 3 3 3
1 1 1 2 3 3 3
4 4 4 5 6 6 6
7 7 7 8 9 9 9
7 7 7 8 9 9 9
7 7 7 8 9 9 9
I don't think it is possible. The right tine is going to be the result of x f y and the left tine is x The middle tine will transpose and apply f to the arguments and then transpose the result back. If you take the right f out then there is not a way to have x f y and if the middle f is removed then you do not have f applied to the transpose.
My guess is that you are looking for a primitive that will accomplish the same result with only one mention of f, but I don't know of one.
Knowing the J community someone will prove me wrong!

Understanding J From

In J:
a =: 2 3 $ 1 2 3 4 5 6
Gives:
1 2 3
4 5 6
Which is a 2 3 shaped array.
If I do:
0 1 { a
I (noting that 0 1 is a 2 shaped list) expected to have back:
1 2 3 4 5 6
But got the following instead:
1 2 3
4 5 6
Reading the documentation I was expecting the shape of the index to kinda govern the shape of the answer.
Can someone clarify what I am missing here?
Higher-dimensional arrays may help make this clear. An array with n dimensions has items with n-1 dimensions. When you select an item from ({) a three-dimensional array, your result is a two-dimensional array:
1 { i. 5 3 4
12 13 14 15
16 17 18 19
20 21 22 23
When you select multiple items from an array, the items are assembled into a new array, using each atom of x to select a item of y. This might be where you picked up the idea that the shape of x affects the shape of the result.
2 1 0 2 { 'set'
test
$ 2 1 0 2
4
$ 'test'
4
The dimensions of the result is equal to the dimensions of x plus the dimensions of the items of y. So, if you have a two-dimensional x taking two-dimensional items from a three-dimensional y, you will have a four-dimensional result:
(2 2 $ 1 1 0 1) { i. 5 3 4
12 13 14 15
16 17 18 19
20 21 22 23
12 13 14 15
16 17 18 19
20 21 22 23
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
$ (2 2 $ 1 1 0 1) { i. 5 3 4
2 2 3 4
One final note: the monadic Ravel (,) will reduce the result to a list (one-dimensional array).
, 0 1 { 2 3 $ 1 2 3 4 5 6
1 2 3 4 5 6
, i. 2 2 2 2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
From ({) selects the items of a noun. For 2 3 $ 1 2 3 4 5 6 the items are the two rows because items are the components that make up the noun.
[ a=. 2 3 $ 1 2 3 4 5
1 2 3
4 5 1
0 { a
1 2 3
If you just had 1 2 3 then the items would be the individual atoms.
[ b=. 1 2 3
1 2 3
0 { b
1
If you used 1 3 $ 1 2 3 then there is only one item and the result would be
[ c=. 1 3 $ 1 2 3
1 2 3
0 { c
1 2 3
The number of items can be found with Tally (#), and is the lead dimension of the Shape ($) of the noun.
$ a
2 3
$ b
3
$ c
1 3
# a
2
# b
3
# c
1

Resources