J : creating a family of verbs from an array - j

The following expression shows a truth table for each of the 16 primitive Boolean operations:
(0 b./; 1 b./; 2 b./; 3 b./; 4 b./; 5 b./; 6 b./; 7 b./; 8 b./; 9 b./; 10 b./; 11 b./; 12 b./; 13 b./; 14 b./; 15 b./) ~ i.2
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│0 0│0 0│0 0│0 0│0 1│0 1│0 1│0 1│1 0│1 0│1 0│1 0│1 1│1 1│1 1│1 1│
│0 0│0 1│1 0│1 1│0 0│0 1│1 0│1 1│0 0│0 1│1 0│1 1│0 0│0 1│1 0│1 1│
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
How can I refactor the part in parentheses to remove the duplication?
clarification:
The goal here isn't to produce the table, but rather to learn how to produce new verbs dynamically. In order to reduce the parenthesized expression, I would want to factor out the symbols ; , / and b. , and then replace the numbers with i.10.
The ; symbol is easy enough:
;/i.16
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──┬──┬──┬──┬──┬──┐
│0│1│2│3│4│5│6│7│8│9│10│11│12│13│14│15│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴──┴──┴──┴──┴──┘
But I'm having a hard time finding a way to produce a new verb from each element in the list.
I think maybe I'm looking for some kind of higher-order combinators that allow using & and # with something other than constants.
For example, nn leftBondEach v might make an array of verbs equivalent to n0 & v; n1 & v; ... ; nn & v :
bverbs =: (i.16)(leftBondEach)b. NB. would mean (0 b.; 1 b.; ...; 15 b.)
0 bverbs 0
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│0│0│0│0│1│1│1│1│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
0 bverbs 1
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│1│1│1│1│0│0│0│0│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
I think I need something similar in order to append the / to each function.
Then again, this is J and there's probably a completely different way to approach these problems that I just haven't grokked yet. :)

What about:
<"2#|:#( (i.16) b./~) 0 1
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|0 0|0 0|0 1|0 1|0 0|0 0|0 1|0 1|1 0|1 0|1 1|1 1|1 0|1 0|1 1|1 1|
|0 0|0 1|0 0|0 1|1 0|1 1|1 0|1 1|0 0|0 1|0 0|0 1|1 0|1 1|1 0|1 1|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Just noticing that $ (i. 16) b. /~ 0 1 is 2 2 16, and you'd want to have 16 boxes with size 2x2 ...

The most straight forward conversion, I can think of, is:
(3 :'y b./ ~ i.2') each i.16
edit on clarification
1. You can define something like f =: 4 :';/x b. y', so:
(i.16) f 0
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│0│0│0│0│1│1│1│1│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
(i.16) f 1
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│1│1│1│1│0│0│0│0│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
2. You can "apply" ;/ to (i.16) b. with At (#):
f =: ;/#((i.16) b.)
f 0
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│0│0│0│0│1│1│1│1│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
f 1
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│1│1│1│1│0│0│0│0│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
3. if you want leftBondEach to work on any verb, then it's a conjuction:
leftBondEach =: 2 :';/m v y'
h =: 2 leftBondEach + NB. equiv. to h =: ;/#(2&+)
h 3 4 5
┌─┬─┬─┐
│5│6│7│
└─┴─┴─┘
h =: 0 leftBondEach ((i.16) b.)
h 0
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│0│0│0│0│1│1│1│1│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
h 1
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│0│0│0│0│1│1│1│1│0│0│0│0│1│1│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
4. etc you can reshape the result like jpjacobs did etc.

Related

Pandas optimize look up of values

I have two dataframes simresult and skipper.
Simresult is in the format:
player_id 0 1 2 3 ... 5 6 7 8 9
0 41843 16.38 10.97 0.37 15.38 ... 23.78 38.08 47.21 26.14 11.94
1 17648 30.14 41.08 1.92 0.18 ... 0.00 39.01 41.08 8.54 22.95
2 16500 19.72 14.38 12.99 3.74 ... 17.72 32.70 3.34 0.50 28.66
3 36727 8.96 30.07 28.45 0.00 ... 0.00 20.48 0.00 27.64 2.15
4 10512 46.59 16.94 1.54 0.00 ... 5.89 0.00 18.33 11.24 0.71
.. ... ... ... ... ... ... ... ... ... ... ...
skipper is:
0 1 2 3 ... 6 7 8 9
0 449732 15862 1200230 10261 ... 814904 14622 16129 2500366
1 14759 10325 17769 16163 ... 10934 15862 17851 21540
2 14542 10934 2038972 2038976 ... 2039175 15181 35356 14622
3 11446 35356 10261 17851 ... 538921 16282 14542 34672
4 15806 21540 894408 37481 ... 15862 480013 15860 814065
.. ... ... ... ... ... ... ... ... ...
where each of those cells is a player_id.
I have some code that takes the player_ids from skipper and looks up the value, by column, from simresult then sums the row and gives me a list of lists.
i.e. there are 10 ids per row in skipper, the final output gives me the sum of those 10 ids as looked up in the first column, then the second column, etc.
This code works exactly as intended.
size = skipper.shape[0]
runs = simresult.shape[1]-1
def getScores(r):
slist = []
for s in range(0,size): #size
z = 0
for l in range(0,10):
y = skipper.iloc[s,l]
x = simresult.loc[simresult['player_id'] == y, r].iloc[0]
z += x
z = round(z,2)
slist.append(z)
return(slist)
scores = np.empty((runs,0)).tolist()
for r in range(0,runs):
scores[r] = getScores(r)
Output after I take the list of lists and put it into another df:
0 1 2 3 ... 6 7 8 9
0 73.90 128.52 106.79 151.37 ... 126.81 115.88 139.87 115.43
1 93.51 135.78 130.62 130.72 ... 136.51 133.90 179.96 207.32
2 112.65 174.84 131.14 103.40 ... 159.58 85.81 116.59 158.88
3 83.37 129.34 117.12 64.50 ... 175.28 69.81 142.74 110.61
4 80.90 142.68 90.23 128.25 ... 51.04 141.63 134.30 95.76
.. ... ... ... ... ... ... ... ... ...
My question: Is there a more efficient way to code this lookup nested loop?
Simplifed simresult:
simplified skipper:
0 1 2 3 ... 6 7 8 9
0 449732 15862 1200230 10261 ... 814904 14622 16129 2500366
simplified output:
0 1 2 3 ... 6 7 8 9
0 73.90 128.52 106.79 151.37 ... 126.81 115.88 139.87 115.43
Use the magic of replace
rep_df = df.set_index('player_id')
out = skip.replace(rep_df)
def getScores(c):
rep_df = simresult.set_index('player_id')
out = round(skipper.replace(rep_df[c]).sum(axis=1),2).to_list()
return(out)
Thanks to #BENY for the suggestion. Doing the replace/lookup on one column at a time from the simresult df and then summing that in place gets me exactly what I want -- and at a significantly faster processing time.

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

All list items up to, and including, the first repeated item

Consider:
x =. 0 1 2 3 4 1 3 4 99
v =. [ {.~ (>: # i.&1 # (##~. = #\))
v x NB. => 0 1 2 3 4 1
The behavior is correct. But as you can see, v is shamefully verbose. Is there a better solution?
You want the monad ~: (nub sieve):
v =: {.~ 1 + 0 i.~ ~:
x =: 0 1 2 3 4 1 3 4 99
v x
0 1 2 3 4 1
Code review:
Outside code-golf contexts, don't use #\ in place of i.##. It's too cutesy, hard to maintain, and won't be recognized by the special-code optimizer.
Don't assign to the names x, y, u, v, m, or n (except in special circumstances, and always locally in an explicit context).

FoldList like primitive in J

Mathematica has a built-in function called FoldList FoldList function description. Is there a similar primitive verb in J?
(I know that J has a ^: verb, which is like Nest and FixedPoint.)
To clarify my question, J has dyadic verb, so usually u / x1 x2 x3 becomes x1 u (x2 u x3), which works just like FoldList, with reverse order.
Except if the function u takes y, in a different shape from x. In FoldList there is an initial x. In J, if x3 is a different shape, one has to rely on < to pack it together. For example, one has to pack and unpack
[list =. (;/ 3 3 4 3 3 34),(< 1 2)
+-+-+-+-+-+--+---+
|3|3|4|3|3|34|1 2|
+-+-+-+-+-+--+---+
tf =: 4 : '<((> x) , >y)'
tf/ list
+----------------+
|1 2 3 3 4 3 3 34|
+----------------+
tf/\ |. list
+---+------+--------+----------+------------+--------------+----------------+
|1 2|1 2 34|1 2 34 3|1 2 34 3 3|1 2 34 3 3 4|1 2 34 3 3 4 3|1 2 34 3 3 4 3 3|
+---+------+--------+----------+------------+--------------+----------------+
which is kind of inconvenient. Any better solutions?
u/\ comes very close (if you don't mind the right folding):
+/\ 1 2 3 4
1 3 6 10
*/\1+i.10
1 2 6 24 120 720 5040 ...
(+%)/\7#1. NB. continued fraction of phi
1 2 1.5 1.66667 1.6 1.625 1.61538
edit on your edit:
The first two elements of FoldList are x and f(x,a). In J those two have to be of the same "kind" (shape+type) if you want them on the same list. The inconvenience comes from J's data structures not from the lack of a FoldList verb. If you exclude x from the list, things are easier:
FoldListWithout_x =: 1 : 'u/ each }.<\y'
; FoldListWithout_x 1 2 3 4
┌─────┬───────┬─────────┐
│┌─┬─┐│┌─┬─┬─┐│┌─┬─┬─┬─┐│
││1│2│││1│2│3│││1│2│3│4││
│└─┴─┘│└─┴─┴─┘│└─┴─┴─┴─┘│
└─────┴───────┴─────────┘
>+ FoldListWithout_x 1 2 3 4
3 6 10
(+%) FoldListWithout_x 7#1
┌─┬───┬───────┬───┬─────┬───────┐
│2│1.5│1.66667│1.6│1.625│1.61538│
└─┴───┴───────┴───┴─────┴───────┘
The next logical step is to include a boxed x after making the folds, but that will either require more complex code or a case-by-case construction. Eg:
FoldList =: 1 :'({.y) ; u FoldListWithout_x y'
+ FoldList 1 2 3 4
┌─┬─┬─┬──┐
│1│3│6│10│
└─┴─┴─┴──┘
; FoldList 1 2 3 4
┌─┬─────┬───────┬─────────┐
│1│┌─┬─┐│┌─┬─┬─┐│┌─┬─┬─┬─┐│
│ ││1│2│││1│2│3│││1│2│3│4││
│ │└─┴─┘│└─┴─┴─┘│└─┴─┴─┴─┘│
└─┴─────┴───────┴─────────┘
vs
FoldList =: 1 :'(<{.y) ; u FoldListWithout_x y'
+ FoldList 1 2 3 4
┌───┬─┬─┬──┐
│┌─┐│3│6│10│
││1││ │ │ │
│└─┘│ │ │ │
└───┴─┴─┴──┘
; FoldList 1 2 3 4
┌───┬─────┬───────┬─────────┐
│┌─┐│┌─┬─┐│┌─┬─┬─┐│┌─┬─┬─┬─┐│
││1│││1│2│││1│2│3│││1│2│3│4││
│└─┘│└─┴─┘│└─┴─┴─┘│└─┴─┴─┴─┘│
└───┴─────┴───────┴─────────┘
I guess #Dan Bron's comment deserves an answer. It is discussed with some solutions in http://www.jsoftware.com/pipermail/programming/2006-May/002245.html
if we define an adverb (modified from the link above)
upd =: 1 : 0
:
u&.> /\ ( <"_ x),<"0 y
)
then
1 2 , upd |. 3 3 4 3 3 34
┌───┬──────┬────────┬──────────┬────────────┬──────────────┬────────────────┐
│1 2│1 2 34│1 2 34 3│1 2 34 3 3│1 2 34 3 3 4│1 2 34 3 3 4 3│1 2 34 3 3 4 3 3│
└───┴──────┴────────┴──────────┴────────────┴──────────────┴────────────────┘

How can I perform a scalar product on a matrix of pairs?

I have a matrix Mcontaining pairs (i.e. arrays of size 2). Given a pair p, how can I get a 2D matrix M'containing the result of the scalar product of p and each element of M?
(0, 0) (0, 1) 8 5
M = (1, 0) (1, 1) p = (2, 2) M' = 5 2
(2, 0) (2, 1) 4 1
M and p are defined :
M =. 3 2 2 $ 0 0 0 1 1 0 1 1 2 0 2 1
p =. 2 2
I have an implementation of scalar product in J :
sp =. +/ #: *: #: -
It works on pairs :
0 0 sp p
8
0 1 sp p
5
But not on the full matrix, because of bad length :
p sp M
|length error: sp
| p sp M
How should I deal with that ? This is probably easy for J geniuses, but I'm just a poor newbie.
Use
p sp"1 M
8 5
5 2
4 1
You want sp here to read first-rank cells of M:
<"1 M
┌───┬───┐
│0 0│0 1│
├───┼───┤
│1 0│1 1│
├───┼───┤
│2 0│2 1│
└───┴───┘
so sp"1 will work on each cell (p sp 0 0, p sp 0 1, etc). sp (infinite rank) tries to apply sp once for the whole matrix M.
Likewise sp"2 will apply sp on second-rank cells of M:
<"2 M
┌───┬───┬───┐
│0 0│1 0│2 0│
│0 1│1 1│2 1│
└───┴───┴───┘
so
p sp"2 M
8 5
2 5
0 5
(the pairs: p sp 2 2 $ 0 0 0 1, p sp 2 2 $ 1 0 1 1 and p sp 2 2 $ 2 0 2 1)

Resources