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
and 2
, which (along with communication handles) have unary function syntax. Plainly put, a string argument to 1
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? Well 0
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