

SJT
Forum Replies Created
-
dc: .Q.a -1+ “j”$ sqrt %[;3] -[;8] :: / decrypt dc
371 56 20 251 1091 35 683 683 440
A sequence of unaries is close to an ideal style in q. According to Arthur Whitney, Ken Iverson considered even infix notation as a sequence of unaries, e.g.
2*3+4
as(2*)(3+)4
.Note how qs apply/index dualism allows us to compose a list in with the unary functions.
Goes without saying that all the iteration is implicit
-
Love the train of unaries, !
My teacher made something of C# also being D?, so
q)note:{flip(x?`$'y)rotate:x}[`$"`"vs"C`C#|Db`D`D#|Eb`E`F`F#|Gb`G`G#|Ab`A`A#|Bb`B"] q)note "EADGBE" E A D G B E F A#|Bb D#|Eb G#|Ab C F F#|Gb B E A C#|Db F#|Gb G C F A#|Bb D G G#|Ab C#|Db F#|Gb B D#|Eb G#|Ab A D G C E A A#|Bb D#|Eb G#|Ab C#|Db F A#|Bb B E A D F#|Gb B C F A#|Bb D#|Eb G C C#|Db F#|Gb B E G#|Ab C#|Db D G C F A D D#|Eb G#|Ab C#|Db F#|Gb A#|Bb D#|Eb
-
BaiChens solution uses the Scan form of the Do iterator
rather than the Each iterator
'
I used.Terse q helps us focus on the core of the algorithm. Lets use BaiChens solution as a practice example.
We can rewrite to eliminate the local variable. And, all other things being equal, good q style prefers infix syntax to bracket notation.
q)8{first[x+1]#x+1}1 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9
The addition surely only needs doing once?
q)4{first[b]#b:x+1}1 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
On each iteration the vector argument lengthens. But we need increment only its first item.
q)4{b#b:1+first x}1 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
The pattern
N f1
is easily recognisable as: Dof
N times, starting with 1.Tightening up the algorithm saves CPU, but the Each is faster still.
q)ts:10000 {b:first x+1;b#x+1}[100;1] 438 64560 q)ts:10000 100{b#b:1+first x}1 301 63536 q)ts:10000 {x#'x} 1+til 100 174 63616
On the next episode of the Array Cast (just recorded on Tuesday), Michael Higginson talks about how the terse and interactive APL and q REPLs encourage him to compare multiple solutions in a way he would rarely have time to do when writing Java.
-
This is my favourite, besides being faster! All the iteration is implicit. Lovely use of
where
on an int vector to generate all the items in one hit.Implicit iterations tend to be faster than iterators.
-
Sure!
The rest of the expression returns a nested list of integers
q){x#’x}1+til 4
,1
2 2
3 3 3
4 4 4 4
Remove those spaces? If your brain has been trained by the one potato, two potato* approach of C-like languages, it immediately sees a double loop to work through the result. The vector programmer sees an opportunity to index. Indexing has atomic iteration; it does all the looping we need.
* This delightful expression was used by Joel Kaplan on the Array Cast podcast.
q)"0123456789"[{x#'x}1+til 4] ,"1" "22" "333" "4444"
Q syntax encourages us to replace nested argument brackets with Index (or Index At for unaries) so were not scanning code back and forth. And prefix notation is syntactic sugar for Index At, so the
@
s can disappear.q)count[distinct[[.Q.a[3 17 14 15 26 3 4 0 3]]]] 7 q)count@distinct@.Q.a@3 17 14 15 26 3 4 0 3 7 q)count distinct .Q.a 3 17 14 15 26 3 4 0 3 7 q) q)"0123456789"{x#'x}1+til 4 ,"1" "22" "333" "4444"
Shifting to vector thinking from one potato, two potato takes practice, which is why the Vector Dojo exists. (Its also a lot of fun.)
The last step is to remove the double quotes q uses to display strings. (And the comma it uses to mark a 1-item vector.)
Q inherits much of ks design principle: no unnecessary typing. The console, stdout and stderr are simply the longs
0
,1
and2
, which (along with communication handles) have unary function syntax. Plainly put, a string argument to1
is written to stdout as a side effect.q)1 “til 6”
til 61
But the result of
1
is still 1, and that got written to the console too and followed as usual by a newline. Terminating an expression with a semicolon stops its result being displayed at the console, and is the only good use for a terminating semicolon. (Multiline lambdas use them as separators, which is similar. An expression not followed by a semicolon separator becomes the lambdas result.)q)1 “til 6”; til 6
q)
OK, we ignored the expression result, but we lost the newline too. No unnecessary typing! Instead of joining a newline to the end of each output string, we use the negative of the system handle, which does it for us.
q)1 “til 6n”; til 6
q)-1 “til 6”; til 6
q)-1 “0123456789”{x#’x}1+til 4;
1 22 333 4444
Of course stdout and stderr both default to the console, so where is
0
in all this? Well0
does what the console does: give it a string and it returns the result of evaluating it.q)1+0 “til 6”
1 2 3 4 5 6
-
Eliminating
up
anddn
is a good move, but that doesnt quite work.q)rnd:{(`up`dn`nr!(f ceiling;(f:{string(x z*s)%s:10 xexp y})floor;.Q.f'))[z][;y;x]} q)q:9.638554216867471 q)rnd[q;2;`up] {string(x z*s)%s:10 xexp y}[-_-:][;2;9.638554]
-
Does the job! Note the use of a dictionary where another language would need a control structure.
The
each
can be dispensed with. Bothup
anddn
take vector arguments..Q.f
does not, sod[2]
could be.Q.f'[nd;]
:q)rnd:{[x;nd;m] d:`up`dn`nr!(up[;nd];dn[;nd];.Q.f'[nd;]); (d m) x} q)rnd[q+0 1 2;3;`up] "9.639" "10.639" "11.639" q)rnd[q+0 1 2;3;`nr] "9.639" "10.639" "11.639"
Now: can we eliminate repetition? The
up
anddn
functions differ by only a single keyword. And without delegating one of the modes to.Q.f
?(Hint: a single expression
rnd
is possible, ?80 characters.) -
I speculate its because its the international standard for dates so Prepare Text uses it.
At any rate I should note in the Reference that it does so.
-
Nice! Though I always wonder about using powerful
ssr
to replace just one character with another.q)?[;”-“;] . reverse 1(“.”=) string `date$.z.p “2022-03-03”
(The Zen monks wanted to play.)
-
Elegant! But is the datetime type not deprecated?
-
Too easy? Too unnecessary? Lets kick it up.
q)ts: .z.d+.z.t q).h.iso8601 ts "2022-03-02T09:12:34.684000000" q).dt.fmtd[;ts] each `iso`dmy`mdy "2022-03-02" "2/3/2022" "3/2/2022"
Write
.dt.fmtd
without control words: noif
,do
,while
or Cond. -
Doesnt get easier than that!
But the challenge is to code it in q.
-
Practice is exactly the right idea! You might find Q by Puzzles helpful some simple puzzles with q solutions that illustrate distinctive features of the language.
The Reading Room also has puzzles for practice. You might start with John Earnests collection Cats Cradle and then see how the well-known Fizzbuzz game can be written in q.
Beyond that the Phrasebook is a collection of expressions to do this and that. Well worth studying and maybe you can provide some improvements!
The problems in this years Advent of Code competition are particularly ripe for vector solutions. I have discussed q solutions to the first weeks problems in the Advent of Code group here. In the new year Ill host a regular online vector d?j? for improving q skills.
Stephen