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
Related
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
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
It is hard for me to describe in words what this function does, but I have some working code.
f:{[n;k] sum flip k </: til n}
i:i: 3 4 6 7 13;
f[30;i]
0 0 0 0 1 2 2 3 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5i
In am concerned that the flip operation may be expensive for large input values. Is there a way to do this without the flip that is more efficient?
Being just as concise would be a nice-to-have.
For your inputs you can achieve the same result with
{[n;k] k binr til n}
This should work so long as k remains in ascending order.
Docs for binr are here: https://code.kx.com/q/ref/bin/
Seans answer is probably more efficient (test it), but why not change your each-right to each-left to avoid the flip?
q)g:{[n;k] sum k<\:til n}
q)f[30;i]~g[30;i]
1b
I'm struggling to understand this q code programming idiom from the kx cookbook:
q)swin:{[f;w;s] f each { 1_x,y }\[w#0;s]}
q)swin[avg; 3; til 10]
0 0.33333333 1 2 3 4 5 6 7 8
The notation is confusing. Is there an easy way to break it down as a beginner?
I get that the compact notation for the function is probably equivalent to this
swin:{[f;w;s] f each {[x; y] 1_x, y }\[w#0;s]}
w#0 means repeat 0 w times (w is some filler for the first couple of observations?), and 1_x, y means join x, after dropping the first observation, to y. But I don't understand how this then plays out with f = avg applied with each. Is there a way to understand this easily?
http://code.kx.com/q/ref/adverbs/#converge-iterate
Scan (\) on a binary (two-param) function takes the first argument as the seed value - in this case 3#0 - and iterates through each of the items in the second list - in this case til 10 - applying the function (append new value, drop first).
q){1_x,y}\[3#0;til 10]
0 0 0
0 0 1
0 1 2
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
6 7 8
7 8 9
So now you have ten lists and you can apply a function to each list - in this case avg but it could be any other function that applies to a list
q)med each {1_x,y}\[3#0;til 10]
0 0 1 2 3 4 5 6 7 8f
q)
q)first each {1_x,y}\[3#0;til 10]
0 0 0 1 2 3 4 5 6 7
q)
q)last each {1_x,y}\[3#0;til 10]
0 1 2 3 4 5 6 7 8 9
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