kdb/q: how to reshape a list into nRows, where nRows is a variable - kdb

If I am to split a list into 2 rows, I can use:
q)2 0N#til 10
However, the following syntax does not work:
q)n:2
q)n 0N#til 10
how I can achieve such reshaping?

Need brackets and semi colon
q)2 0N#til 10
0 1 2 3 4
5 6 7 8 9
q)n:2
q)(n;0N)#til 10
0 1 2 3 4
5 6 7 8 9

Here is the general syntax to split a list in matrix form:
(list1)#(list2)
As you can see, left part and right part of '#' is list. So here is one example:
q)list1: (4;3) / or simply (4 3)
q)list2: til 12
q)list1#list2
We can make an integer list in 2 way:
Using semicolon as list1:(2;3;4)
Using spaces as list1:(2 3 4)
But when you have variable, option 2 doesn't work;
q)list1: (n 3) / where n:2
q) `type error
So for your question, solution is to use semicolon to create list:
q) list1:(n;0N)
q) list1#til 10

Related

Merge 2 lists according to values in a boolean list

I have a method of achieving this which also explains my question.
a:1 2 3 4;
b:5 6 7;
cond:1101001b;
comb:(count cond) # 0N;
comb[where cond]:a;
comb[where not cond]:b
But q has so many utilities for manipulating lists, I am wondering if there is a more direct way of doing this.
rank is what you need.
q)comb
1 2 5 3 6 7 4
q)(b,a)rank cond
1 2 5 3 6 7 4
You could write the expression in a single line
comb:#[;where not cond;:;b] #[;where cond;:;a] (count cond)#0N
Alternatively, assuming the 1s and 0s of cond matches the lengths of a and b:
(a,b) iasc where[cond],where not cond

How do I evaluate a function into a matrix in KDB?

Let's say I've got a function that defines a matrix in terms of it's i and j coordinates:
f: {y+2*x}
I'm trying to create a square matrix that evaluates this function at all locations.
I know it needs to be something like f ' (til 5) /:\: til 5, but I'm struggling with rest.
Rephrasing your question a bit, you want to create a matrix A = [aij] where aij = f(i, j), i, j = 0..N-1.
In other words you want to evaluate f for all possible combinations of i and j. So:
q)N:5;
q)i:til[N] cross til N; / all combinations of i and j
q)a:f .' i; / evaluate f for all pairs (i;j)
q)A:(N;N)#a; / create a matrix using #: https://code.kx.com/q/ref/take/
0 1 2 3 4
2 3 4 5 6
4 5 6 7 8
6 7 8 9 10
8 9 10 11 12
P.S. No, (til 5) /:\: til 5 is not exactly what you'd need but close. You are generating a list of all pairs i.e. you are pairing or joining the first element of til 5 with every element of (another) til 5 one by one, then the second , etc. So you need the join operator (https://code.kx.com/q/ref/join/):
(til 5),/:\: til 5
You were close. But there is no need to generate all the coordinate pairs and then iterate over them. Each Right Each Left /:\: manages all that for you and returns the matrix you want.
q)(til 5)f/:\:til 5
0 1 2 3 4
2 3 4 5 6
4 5 6 7 8
6 7 8 9 10
8 9 10 11 12

Except (^ or _dvl) analog in k4, 8 Queens example

I've just played with 8 Queens puzzle, and found out that it seems there is no _dvl operator (from k(v2)) in k(v4). Also I checked other k versions from ngn k impls and found ^ operator in k(v6), for example at JohnEarnest's impl:
l^a or l^l is except. Remove all instances of each of y from x.
k) 1 3 2 5 1 2 3^1 3 5
2 2
I really love SQL-style and would like to apply it in q. But is the following way idiomatic in q/k(v4) and is it a good solution? Or maybe there are shorter ways to do such list comparison/exclusion exists:
q)show s:til 8
0 1 2 3 4 5 6 7
q)s where not s in 2 4 6 /bother about this line, can it be shorter?
0 1 3 5 7
My version of q8 code is a bit longer then in nsl k2, without recursion and without conditions:
f:{raze {(x,) each (til 8) where not (til 8) in {x,(x-f),x+f:reverse 1+til count x} x} each x}
\ts:10 7 f/til 8 /248 100128
count 7 f/til 8 /92
first 7 f/til 8 /0 4 7 5 2 6 1 3
Upd: command I was looking for is except:
q)f:{raze {(x,) each (til 8) except {x,(x-f),x+f:reverse 1+til count x} x} each x}
Upd2: generalized 8 Queens solution in k(v4):
k){(x-1){,/{(x,)'(!y)#&~(!y)in{x,(x-f),x+f:|1+!#x}x}[;y]'x}[;x]/!x}8
Upd3: add 8 queens puzzle to blog
It is just keyword except.
How to find it: we know idiomatic k construction #&, so just search through .q namespace for it:
q)qfind:{([] q:k;k:.q k:key[.q] where (string value .q) like "*",x,"*")}
q)qfind "#&"
q k
-----------------------------------
inter k){x#&x in y}
except k){x#&~x in y}
xcols k){(x,f#&~(f:cols y)in x)#y}
q) (til 8) except 2 4 6
0 1 3 5 7

Can you append the elements of one list to those of another without iterating through the lists in Q?

I am trying to add the elements of one list to another with the desired output as seen below.
I've attempted joining the lists with the , operator but this does not create the desired results:
q)l1: (1 2 3; 5 6 7)
q)l2: (4 8)
q)l1,l2
(1 2 3; 5 6 7;4;8)
Desired result: (1 2 3 4; 5 6 7 8)
I'm wondering if there's any built-in ability to do this in q as my understanding is that having to iterate through these vectors would be inefficient in q.
You can achieve it by doing the following which will join each element of the left with each element of the right
q)l1: (1 2 3; 5 6 7)
q)l2:(4 8)
q)l1,'l2
1 2 3 4
5 6 7 8

Pass multiple arguments to a function within select

I'd like to calculate a new column which is a function of several columns using select.
My actual application will involve a grouping in the select so the columns entries which I will pass to the function will contain lists. But this simple example illustrates my question
t:([] a:1 2 3; b:10 20 30; c:5 6 7)
/ Pass one argument, using projection (set first two arguments to 1)
select s:{[x;y;z] x+y+z}[1;1;] each a from t
/ Pass two arguments using each-both (set first arg to 1)
select s:a {[x;y;z] x+y+z}[1;;]'b from t
Now, how can I pass three or more arguments?
Each' will work in general but it's best to use vector operations where possible. Here I use the . operator to apply our function, \t to time both methods. I store their results to r1/r2 to show they are the same:
q)t:([]a:til n;b:til n;c:til n:1200300)
q)\t r1:update d:{x+y+z}'[a;b;c] from t
289
q)\t r2:update d:{x+y+z} . (a;b;c) from t
20
q)r1~r2
1b
q)r2
a b c d
-----------
0 0 0 0
1 1 1 3
2 2 2 6
3 3 3 9
4 4 4 12
5 5 5 15
..
Cheers,
Ryan
The following form works in general
q)t:([]a:til 10;b:til 10;c:til 10)
q)select d:{x+y+z}'[a;b;c] from t
d
--
0
3
6
9
..