Keywords
all
Everything is true
min$["b"]
This takes advantage of the fact that any value can be cast to a boolean and return 0b if the value is 0 and 1b otherwise.
In this case, the input is cast to a boolean, and the minimum boolean value is taken from the result.
As such, if there are any values which are 0 in the input, those will return 0b when cast to boolean, and will be the minimum boolean value, hence the result would be 0b.
q)list:1 2 3 0 -1
q)"b"$list
11101b
q)min "b"$list
0b
q)all[list]~min "b"$list
1b
any
Something is true
max$["b"]
This works exactly the same as 'all' but uses 'max' instead of 'min' to show if any of the boolean values are true.
asc
Ascending sort
Sort and grade: ascending
k){$[99h=@x;(!x)[i]!`s#r i:<r:. x;`s=-2!x;x;0h>@x;'`rank;`s#x@<x]}
{
$[99h=type x;
(key x)[i]!`s#r i: iasc r:value x;
`s=attr x;
x;
0h>type x;
'`rank;
`s# x iasc x
]
}
Check if x is a dictionary. If so:
Sort the values of the dictionary in ascending order and apply the sorted attribute - use this order to sort the keys too, and make a new dictionary with both.
If not: check if x is already sorted (has the sorted attribute applied). If so:
Return x
If not: check if x is an atom. If so:
Return `rank error (can't sort one item)
Else:
Sort x in ascending order and apply the sorted attribute
avgs
Running averages
k){(+\x)%+\~^x}
(sums x) % sums not null x
This is smart and simple. Take the running sum of x, and divide it by the running count of non-null items in x.
ceiling
Round up
-_-:
neg floor neg x
Apply the in-build kdb 'floor' function '_' on the negative of x, which will round it 'up' closer to 0. Apply neg again to get back to original sign.
cols
Column names of a table
{$[.Q.qp x:.Q.v x;.Q.pf,!+x;98h=@x;!+x;11h=@!x;!x;!+0!x]}
{
$[.Q.qp x:.Q.v x;
.Q.pf,!+x;
98h= type x;
key flip x;
11h=type key x;
key x;
key flip 0!x
]
}
Get the table x (if it is a filepath, get the table at that filepath)
Check if it is a partitioned table, if so:
Flip it and get the keys (see here for what happens when you flip a partitioned table), join this to the partition column derived from Q.pf.
If not, check if the table is a standard unkeyed table. If so:
Flip it and get the keys of the resulting dicitonary
If not, it must be a keyed table or dictionary. Check if it is a keyed table by applying 'key' to it - on a dictionary this returns a list of syms (the keys of the dict). If this is what is returned:
Return the keys of x
If not (and it is a keyed table):
Unkey the table, flip it and get the keys of the resulting dictionary
cross
Cross-product
k){n:#m:&(#x)##y;$[99h=@x;((!x)[m],'n#!y)!(. x)[m],'n#. y;((),x)[m],'n#y]}
{
n:count m:where (count x) # count y;
$[99h= type x;
(key[x][m],'n#key[y])!(value x)[m],'n#value y;
((),x)[m],'n#y
]
}
Create a list of counts that will match the shape of the final result lists - i.e. if we are crossing a list of count 2 and a list of count 3, create a list of two 3s.
Use the 'vector of non-negative integers' behaviour of where to create a list 'm' which fleshes out the list created in #1 i.e. it will now be a list of three 0s and three 1s. Assign 'n' to be the count of this list (final count of values).
If x is a dictionary:
Calculate result dictionary values:
Take 'n' of the value of 'y' - this will duplicate the values of 'y' to the desired length of the final results
Join (each both) this to the result of indexing into the values of 'x' with 'm' - this will duplicate the values of 'x' to the desired length of the final results
Calculate result dictionary keys:
Take 'n' of the key of 'y' - this will duplicate the keys of 'y' to the desired length of the final results
Join (each both) this to the result of indexing into the keys of 'x' with 'm' - this will duplicate the keys of 'x' to the desired length of the final results
If not:
Take 'n' of y - this will duplicate 'y' to the desired length of the final results
Join this to the result of indexing into 'x' with 'm' - this will duplicate 'x' to the desired length of the final results
cut
Cut a list or table into sub-arrays / cut a list or table into a matrix of x columns
k){$[0h>@x;x*!-_-(#y)%x;x]_y}
{
$[0h>type x;
x* til ceiling (count y)%x;
x
]_ y
}
If x is an atom:
Find the indices at which to cut x. E.g. 3 cut 1 2 3 4
Divide the count of y by x, round up the result = 2
Multiply x by 'til 2' = 0 3
The answer is now '0 3 _ y' (see cut operator)
If not:
The answer is simply 'x _ y' (see cut operator)
desc
Sort and grade: descending
k){$[99h=@x;(!x)[i]!r i:>r:. x;0h>@x;'`rank;x@>x]}
{
$[99h=type x;
(key x)[i] ! r i: idesc r:value x;
0h>type x;
'`rank;
x idesc x
]
}
Check if x is a dictionary, if so:
Re-sort the values using idesc
Re-sort the keys using the same order used to re-sort the keys
If not, check if x is an atom, if so:
Return `rank error (cannot sort an atom)
Else:
Sort x using idesc
differ
Find where list items change value
$["b"]~~':
"b"$not (~) prior x
Using the each prior iterator, check if each item in the list matches the previous item in the list. Inverse this to return 'true' where each item in the list does NOT match the previous item.
Note: not sure why there needs to be a cast here.
dsave
Write global tables to disk as splayed, enumerated, indexed kdb+ tables.
k){.[*x;1_x,y,`;:;@[;*!+a;`p#].Q.en[*x]a:. y];y}/:
{
.[first x; 1_x,y,`; :;
@[;*!+a;`p#].Q.en[first x]a:value y
];
y
}/:
ema
Exponential moving average
k){(*y)(1f-x)\x*y}
(first y) (1f-x)\x*y
To better understand this we must understand the formula for the exponential moving average (EMA):
EMA = Closing price * multiplier + EMA (previous day) * (1-multiplier)
So let's break it down, with the following inputs, x:2, y:2 2 3 1
x*y
Get all of the 'closing price * multiplier' values i.e. 4 4 6 2
(first y)(1f-x)\
This is a scan with (first y) as the first input and (1f-x) as the function.
(first y) is 2
(1f-x) is -1f
This gives us (2) (-1f)\4 4 6 2
This is easier written as
2{y+x*-1}\4 4 6 2
For each of the items we are iterating over:
If it is the first item, take x as 2 and perform the function with y as the first value in the input list, with the result becoming the 'x' for the next input
For each subsequent input, take the result of the previous input as x and the current input as y and perform the function
As it is a scan, return each result
Result: 2 2 4 -2
except
Exclude items from a list
k){x@&~x in y}
x where not x in y
Self-explanatory.
fkeys
Foreign-key columns of a table
k){(&~^x)#x:.Q.fk'.Q.V x}
(where not null x)#x:.Q.fk each .Q.V x
Turn the table into a dictionary
Check if any of the cols (now key/value pairs in the dict) are foreign keys
Return the key/pair values from the dictionary where this is the case
gtime
Convert timestamp to UTC.
k){t+x-%t:x+x-%x}
diff:(.z.P-.z.p);
t + x - diff + t: x + x - diff + x
This makes use of the (apparently undocumented) override of '%' in k (see ltime), which adds the difference between the shell timezone and UTC to the input.
This has been represented above by subtracting .z.P and .z.p.
Subtract x from x+diff to get the number of hours needed to go from UTC to current shell timezone.
Repeat this. Why?
hsym
Symbol/s to file or process symbol/s
$["s"]!'[-1]
"s"$-1!'x
Basically this just making use of the -1! internal function.
iasc and idesc
Ascending grade / descending grade
k){$[0h>@x;'`rank;<x]}
k){$[0h>@x;'`rank;>x]}
Return a rank error if x is an atom. Otherwise, use the k ascend/descend operator.
inter
Intersection of two lists or dictionaries
k){x@&x in y}
x where x in y
Self-explanatory.
keys
Key column/s of a table
{$[98h=@x:.Q.v x;0#`;!+!x]}
{
$[98h=type x:.Q.v x;
0#`;
key flip key x
]
}
Get the value of x (as a symbol reference may have been passed in rather than the actual table)
If it's a normal table, return a list of one `
If it's a keyed table, key it to get the key column(s), flip that to get a dictionary where the column name(s) is/are the key, and return the key.
load
Load binary data from a file
k){$[1=#p:`\:*|`\:x:-1!x;set[*p;. x];set[*p].h.xt[p 1]@0:x]}'
{
$[1=count p:` vs first reverse ` vs x:hsym x;
set[first p; get x];
set[first p; .h.xt[p 1; read0 x]
} each x
According to code.kx, input can be one of: a symbol of a file in the current dir (with no file extension), a filehandle (with no file extension) or a directory.
The 'false' statement in this code is only valid when the input is a json file with a '.json' filepath. I am unable to see this documented on the main code.kx website.
For each input apply the following logic:
Use hsym to ensure the input is a filepath and check if it has a file extension or not. If not:
Use 'set' to set as a global variable either the filename or the directory name, to the result of 'getting' the file/filepath/directory.
If so:
Use 'set' to set as a global variable either the filename or the directory name, to the result of reading in the json file with .h.xt
lower
Shift case
k){$[$[(~@x)&10h~@*x;&/10h=@:'x;0b];_x;~t&(77h>t)|99h<t:abs@@x;.z.s'x;19h<t;.z.s@. x;~t in 10 11h;'`type;_x]}
{
isMixedListOfStrings:$[(not type x)&10h~type first x;
min 10h= type each x;
0b
];
$[isMixedListOfStrings;
_x;
not t&(77h>t)|99h<t:abs type x;
.z.s each x;
19h<t;
.z.s get x;
~t in 10 11h;
'`type;
_x
]
}
Check if we are dealing with a mixed list that consists entirely of strings. If so:
Lower it using the k operator _
If not: check if this is a mixed list, anymap, mapped nested list (see here), table or a dictionary . If so:
Perform the 'lower' func on each item of the list
If not: check if the abs type of x is a non-basic datatype (e.g. enumeration). If so:
Perform the 'lower' func after getting x
If not: check if the abs type of x is anything other than symbol or string. If so:
Type error
Else: lower it using the k operator _
ltime
Convert UTC timestamp to local time.
%:
x + (.z.P - .z.p)
This uses the k verb '%' which does not appear to be well documented. Essentially it uses the shell timezone setting e.g.
(UTC-05:00) Eastern Time (US & Canada)
Eastern Standard Time
And basically performs the calculation from there (in this example it would subtract 5 hours from the timestamp)
ltrim
Remove leading nulls from a list
k){$[~t&(77h>t)|99h<t:@x;.z.s'x;^*x;((^x)?0b)_x;x]}
{
$[not t&(77h>t)|99h<t:type x;
.z.s each x;
null first x;
((null x)?0b)_x;
x
]
}
Check if this is a mixed list, anymap, mapped nested list (see here), table or a dictionary . If so:
Perform the 'ltrim' func on each item of the list
If not: check if the first item in x is null. If so:
Find the index of the first non-null item in x
Drop that many records from the start of x
If not: return x
mavg
Moving averages
k){msum[x;0.0^y]%mcount[x;y]}
{
msum[x;0.0^y]%mcount[x;y]
}
Take the mcount of x and y (this will eventually 'max out' at x e.g. mcount[2;1 2 3 4 5] is 1 2 2 2 2)
Perform division with this list as the denominator and the running sum of x and y as the numerator
Ensuring to fill any nulls of y with 0.0
This is dividing the running sum with the running count over the same values, producing a moving average.
mcount
Moving counts
k){msum[x;~^y]}
{
msum[x;not null y]
}
Easy - take a boolean list where y is not null and simply run an msum against it.
mdev
Moving deviations
k){sqrt mavg[x;y*y]-m*m:mavg[x;y:"f"$y]}
{
sqrt mavg[x;y*y] - m*m:mavg[x;y:"f"$y]]
}
Get the moving average of x and y (cast y to a float - mdev can take any type which can be sucessfully cast to a numerical type including booleans and temporal types)
Square this, and subtract the result from the moving average of x and y squared
Return the square root of this
med
Median
k){avg x(<x)@_.5*-1 0+#x,:()}
{
if[1=count x; x:enlist x];
avg x (iasc x) floor .5*-1 0+count x
}
Find the 'middle two' values of the list
Get the second last and last index of x
Divide these by 2 and round down
For a list with even count, this will be the index just before and the index just after the middle
For a list with odd count, this will return the middle index twice
Get the values of x at those indices (sort x in ascending order if needed)
Find the average of these two values
meta
Metadata for a table
{([!c].Q.ty't;f:.Q.fk't;a:-2!'t:. c:.Q.V x)}
{
a:attr each t:value c:.Q.V x;
f:.Q.fk each t;
([key c] .Q.ty each t; f; a)
}
Create a table with:
Key column which contains the columns of the input table
Column 't' with the types of each column
Column 'f' with the foreign keys of each column
Column 'a' with the attributes of each column
mins
Minimums
&\
(&) scan x
This is utilising the 'lesser' operator with the 'scan' iterator to take each item in the list, compare it with the next one, and return the lesser of the two. Repeat until the entire list has been traversed.
mmin and mmax
Moving minimums / moving maximums
k){(x-1)&':/y}
k){(x-1)|':/y}
(&':)/[3;4 2 3 4 0 4 3 2 2 10 9 0 9 3]
or, for easier understanding:
do[x-1; y:(&) prior y]; y
To understand these you must first understand the 'do' iterator and the each-prior (':) iterator.
This performs the same action x-1 times: traverse the list and compare the value of the current item with the item before it (min or max), replace the current value with the previous value if it is indeed greater or less than the current value.
By repeating this x-1 times, the result is essentially an x-1 moving min/max.
mmu
Matrix multiply, dot product
$
There isn't much to explain here! If you are not familiar with matrix multiplication, best to brush up on it.
mod
Modulus
k){x-y*x div y}
{x-y*x div y}
This is simple maths - find the number of times y goes into x, multiply that by y to get the full amount and then take that from x to return the remainder.
msum
Moving sums
k){$[99h=@y;(!y)!.z.s[x;. y];y-(-x)_(0i*x#y),y:+\y]}
{
$[99h=type y;
(key y)!.z.s[x;value y];
y- neg[x]_(0i*x#y),y: sums y
]
}
Check if x is a dictionary. If so:
Return a dictionary with key set to the key of x, and value set to the result of running the msum function against the values of x
If not:
Join x number of 0s to the result of sums y and set the result to y
e.g. with '3 msum 1 2 3 4 5' this value is now 0 0 0 1 3 6 12 19 27
Remove x values from the end of that list i.e. the value is now 0 0 0 1 3 6
Take this value away from 'y' i.e. the value is now 1 3 6 12 19 27
Essentially, there will be no difference between 'msum' and 'sums' for the first x numbers, which is why that is the number of zeroes added to the front - deducting 0 from the running sum just returns the running sum so far. For the next numbers, they are essentially the 'updated' running sum i.e. starting from the first non-zero, deducted from the total running sum.
next
Next item/s in a list
k){$[0h>@x;'`rank;1_x,,x 0N]}
{
$[0h > type x;
'`rank;
1_x,,x 0N
]
}
If is not a list, return a type error. Else:
Return the same list but with the first value removed and a null value added.
parse
Parse a string
k){$["\\"=*x;(system;1_x);-5!x]}
{
$["\\" = first x;
(system;1_x);
-5!x
]
}
This is basically a wrapper for the -5! internal function.
There is one check if the string represents a system command (with two backslashes as the first would be an escape character). In this case the parse returns a parsed system command.
rand
Pick randomly
k){*1?x}
first 1?x
Uses the 'roll' overload of the question mark character. Just using a 1?x returns a one item list, so 'first' ensures it is an atom.
rank
Position in the sorted list
k){$[0h>@x;'`rank;<<x]}
{
$[0h > type x;
'`rank;
iasc iasc x
]
}
Fail with a rank error if not a list. Otherwise:
Perform iasc once to get the positions of where each item in the list should be if sorted, then perform it again to show at each position, which item in the list should be there.
rload
Load a splayed table from a directory
k){x:-1!x;.[*|`\:x;();:;. x]}'
{
x: hsym x;
.[first reverse ` vs x; (); :; get x]
} each x
For each input (splayed table):
hsym it to ensure it's a filepath
Globally set the variable at the end of the filepath (table name) to 'get x'
Still trying to figure out what all the whitespace is for...
rotate
Shift the items of a list to the left or right
k){$[0h>@y;'`rank;98h<@y;'`type;#y;,/|(0;mod[x;#y])_y;y]}
{
$[0h > type y;
'`rank;
98h < type y;
'`type;
count y;
,/|(0;mod[x;count y])_y;
y
]
}
If y is not a list:
Throw a rank error
If it is, check if y is a dictionary, keyed table, or any other type greater than 98h. If it is:
Throw a type error
If not, check if y has a count of 1 or greater. If it does:
wdaw
If not:
Return y
rsave
Write a table splayed to a directory
k){x:-1!x;.[`/:x,`;();:;.*|`\:x]}'
{
x:hsym x;
.[` sv x,`; (); :; get first reverse ` vs x]
} each x
This is essentially getting the table named x and setting it down (using dot amend) with filename 'x' in the current directory.
rtrim
Remove trailing nulls from a list
k){$[~t&(77h>t)|99h<t:@x;.z.s'x;^last x;(-(|^x)?0b)_x;x]}
{
$[not t&(77h>t)|99h<t:type x;
.z.s each x;
null last x;
(-(reverse null x)?0b)_x;
x
]
}
Check if this is a mixed list, anymap, mapped nested list (see here), table or a dictionary . If so:
Perform the 'rtrim' func on each item of the list
If not: check if the last item in x is null. If so:
Find the index of the first non-null item when x is reversed
Drop that many records from the end of x
If not: return x
save
Write a global variable to file
k){$[1=#p:`\:*|`\:x:-1!x;set[x;. *p]; x 0:.h.tx[p 1]@.*p]}'
{
$[1=count p:` vs first reverse ` vs x:hsym x;
set[x; get first p];
x 0: .h.tx[p 1; get first p]
]
} each x
According to code.kx, input can be one of: a symbol of a file in the current dir (with no file extension), a filehandle (with no file extension) or a directory.
The 'false' statement in this code is only valid when the input is a json file with a '.json' filepath. I am unable to see this documented on the main code.kx website.
For each input apply the following logic:
Use hsym to ensure the input is a filepath and check if it has a file extension or not. If not:
Use 'set' to set as a global variable either the filename or the directory name, to the result of 'getting' the file/filepath/directory.
If so:
Use 'set' to set as a global variable either the filename or the directory name, to the result of reading in the json file with .h.xt
scov
Sample covariance
k){(n*cov[x;y])%-1+n:(#x)-+/^x+y}
{
(n*cov[x;y])%-1+n:(#x)-+/^x+y
}
sdev
Standard deviation
k){sqrt svar x}
{
sqrt svar x
}
This is simply getting the square root of the sample variance of x.
set
Assign a value to a global variable / persist an object as a file or directory
k){$[@x;.[x;();:;y];-19!((,y),x)]}
{
$[type x;
.[x;();:;y];
-19!((,y),x)
]
}
Check if 'x' is a mixed list. If not:
Use the functional form of apply to perform the actual set logic
If so, the 'x' arguments must be compression arguments:
Use the 19! internal function to perform the set in this case
show
Format and display at the console.
k){1 .Q.s x;}
{
1 .Q.s x;
}
Writes the output of .Q.s[x] to the stdout file handle. As the file handle is returned when that query is successful, there is a deliberate semi-colon added to prevent any return value.
signum
Sign function
k){(x>0)-x<0}
{
(x>0)-x<0
}
Two boolen lists are created: one showing where x is greater than 0 and one showing where x is less than 0.
When these lists are subtracted, positive numbers return 1, negative numbers return -1 and 0 returns 0.
ssr
Search string replace
k){,/@[x;1+2*!_.5*#x:(0,/(0,{n:x?"[";$[n=#x;n;n+.z.s$[(#x)=p:x?"]";'"unmatched ]";p]_x:(n+2+"^"=x n+1)_x]}y,"")+/:x ss y)_x;$[100h>@z;:[;z];z]]}
numberOfChars:{
n:x?"[";
$[n=count x;
n;
[
x:(n+2+"^"=x n+1)_x;
n+.z.s $[(count x)=p:x?"]"; '"unmatched ]"; p] _x
]
}
y:y,"";
ind:(0,numberOfChars y);
ind:(0,/(ind)+/:x ss y)_x;
ind:1+2*til floor .5 * count ind;
raze @[x; ind; $[100h > type z; :[;z]; z]]
This one is quite long so has been slightly re-organised to (hopefully) make it clearer.
Enlist y (if it is not already a list)
Use the 'numberOfChars' function to find the number of characters that need to be replaced. 'ssr' can accept a regex input which means that square brackets may be used. Although there may be multiple characters inside the square brackets, only one will actually get a match for replacement. This function accounts for this.
Find where the matches occur and cut x at these points.
Identify the indices in the cut parts that represent the matched phrases that need to be replaced.
Perform the actual replacement using at apply. The method of applying 'z' will be different if z is a iterator, composition, etc.
sublist
Select a sublist of a list
k){$[99h=@y;sublist[x;!y]!sublist[x;. y];~0h>@x;$[.Q.qp y;.Q.ind[y];y]i+!"j"$0|x[1]&(#y)-i:*x;abs[x]<#y;x#y;y]}
{
$[99h=type y;
sublist[x;key y]!sublist[x;value y];
not 0h>type x;
$[.Q.qp y;
.Q.ind[y];
y
]i+til "j"$0|x[1]&(count y)-i:first x;
abs[x]<count y;
x#y;
y
]
}
Check if y is a dictionary, if so:
Just run this same function separately on the keys and the values, and return the results of both as a dictionary
If not, check if x is a list (it should be only a two item list). If so:
Figure out what is going to be returned:
Subtract the first item in x from the count of y, this is how many items from y will be returned if the second number in x is greater than the count of y
Compare this to the second number in x, and take whichever is smaller, this caters for the scenario where the items in x are truly a sublist of the indices of y
Compare this to 0 and take whichever number is larger, this caters for negative cases
If y is not a partitioned table, return that value. If y is a partitioned table, use .Q.ind to return those indices from the table
If not and x is an atom:
Check if the value in x is greater than the entire count of y
If not, take x indices from y
If so, just return y
sv
Scalar from vector
k){x/:y}
svar
Sample variance
k){(n*var x)%-1+n:(#x)-+/^x}
{
(n*var x)%-1+n:(count x)-sum null x
}
Get the 'n' count which is the count of non-null values of x
Subtract 1 from 'n'
Divide (n * var x) by the result of #2.
system
Execute a system command
.,["\\"]
value "\\", x
tables
List of tables in a namespace
k){."\\a ",$$[^x;`;x]}
{
system "a ", string $[null x;`;x]
}
This is basically running \a x
til
First x natural numbers
k){$[0>@x;!x;'`type]}
{
$[0> type x;
(!)x;
'`type
]
}
This just makes use of the ! operator in k which is essentially 'til'
trim
Remove leading and trailing nulls from a list
k){ltrim rtrim x}
{
ltrim rtrim x
}
See the sections on ltrim and rtrim.
ungroup
Ungroup
k){$[#x:0!x;,/+:'x;x]}
{
$[count x:0!x;
raze flip each x;
x
]
}
This takes advantage of the following behaviour in 'flip':
If an atom(s) are provided, they are extended to match the length of the list(s).
upper
Shift case
k){$[$[(~@x)&10h~@*x;&/10h=@:'x;0b];.Q.Aa x;~t&(77h>t)|99h<t:abs@@x;.z.s'x;19h<t;.z.s@. x;~t in 10 11h;'`type;$[11h=t;`$.Q.Aa@$x;.Q.Aa x]]}
{
isListOfStrings:$[(not type x)&10h~type first x;min 10h=type each ;0b];
$[isListOfStrings;
.Q.Aa x;
not t and (77h>t) or 99h<t:abs type x;
.z.s each x;
19h<t;
.z.s value x;
not t in 10 11h;
'`type;
$[11h=t;`$.Q.Aa string x;.Q.Aa x]
]
}
Check if x is a list of strings, if so:
Use .Q.Aa to convert them all to uppercase (this is undocumented)
If not, check if x is either a mixed list (type 0) or a mapped list, table or dictionary (types 77-99). If it is:
Perform this same function against each item in the list/table/dictionary
If not, check if x is an enum type (types 20-76). If it is:
Perform this same function against 'value x'
If not, check if x is a symbol or string. If it isn't, return a type error, if it is:
Use .Q.Aa to convert all values to uppercase (string it first if it's a symbol)
upsert
Overwrite or append records to a table
.[;();,;]
This uses the general form of apply to add the new records to the table using the ',' binary operator. This also gives the intended behaviour for keyed tables as joining a dictionary to a dictionary with the same key will overwrite the value in that key:
q)(`a`b!1 2),`b`c!10 20
a| 1
b| 10
c| 20
view
Expression defining a view
k){$`. .`\:x}
{
string `.[` vs x]
}
A view will exist in the root namespace i.e. `.
'view' retrieves it from the root namespace.
views
List views defined in the default namespace
k){."\\b ",$$[^x;`;x]}
{
system "b ",string $[null x;`;x]
}
This is using the system "b" command which lists views in the provided namespace.
Note this function implies that you can define views in the non-default namespace - please see this stackoverflow answer by Igor Korkhov for more details.
vs
Vector from scalar
k){x\:y}
ww
k){[a;w;f;y;z]f,:();e:1_z;z:*z;y,'n#+(:/'f)!+{[e;d;a;b]e .'d@\:\:a+!b-a}[*:'e;z f:1_'e]/'$[n:#*w;+$[#g;(g#z)?g#y;0]|/:a+$[#g:-1_f;(f#z)bin@[f#y;*|f;:;]@;z[*f]bin]'w;,0 0]}
This is not documented.
xasc
Sort a table in ascending order of specified columns.
k){$[$[#x;~`s=-2!(0!.Q.v y)x;0];.Q.ft[@[;*x;`s#]].Q.ord[<:;x]y;y]}
{
notEmptyOrAlreadySorted:$[count x; not `s=attr (0!.Q.v y)x;0];
$[notEmptyOrAlreadySorted;
.Q.ft[ @[;first x;`s#]; .Q.ord[iasc;x;y]];
y
]
}
If y is empty or already sorted on x, return y.
Otherwise, sort y on x using .Q.ord, apply the sorted attribute and return it via .Q.ft in case it's a keyed table.
xbar
Round down
k){x*y div x:$[16h=abs[@x];"j"$x;x]}
{
x:$[16h=abs[type x]; "j"$x; x];
x*y div x;
}
Perform 'y div x' to find out how many times x goes into each y, multiply this by 'x' again (similar to rounding down to the nearest whole x).
I am not sure why timespan gets special treatment here over the other temporal types.
xcol
Rename table columns
k){.Q.ft[{+$[99h=@x;@[!y;(!y)?!x;:;. x];x,(#x)_!y]!. y:+y}x]y}
{
renameColsFunc:{
flip $[99h=type x; @[key y; (key y)?key x; :; value x]; x,(count x)_key y]!value y:flip y
}[x;];
.Q.ft[renameColsfunc;y]
}
For the function that performs the column renames:
Create a final table by flipping a dictionary, the values of which is the data in table y. The keys of the dictionary depend on the x argument.
Check if the x argument is a dictionary (of renameFrom!renameTo pairs) If so:
Update the keys of the final dictionary to be the columns of 'y' overwritten where there are matches in the key of dict 'x'
If not:
Overwrite the column names from y with the values from x by removing 'count x' items from the front, this ensures that you can e.g. rename the first 4 cols of a 10 col table
Finally, put this function through .Q.ft with the arguments provided, this ensures the function will perform on keyed and unkeyed tables
xcols
Reorder table columns
k){(x,f@&~(f:cols y)in x)#y}
{
(x,f where not (f:cols y)in x)#y
}
Take columns from table y starting with those specificed in list 'x' and followed by any leftover in their original order.
xdesc
Sorts a table in descending order of specified columns.
k){$[#x;.Q.ord[>:;x]y;y]}
{
$[count x; .Q.ord[idesc; x; y]; y]
}
Use .Q.ord to sort table y descending by column x.
xgroup
Groups a table by values in selected columns
k){x,:();a:x#y:0!y;$[#x_:y;+:'x@=a;a!+f!(#f:!+x)#()]}
{
x,:();
a:x#y:0!y;
$[count x:x _ y;
flip each x group a;
a! flip f!(count f:key flip x)#()
]
}
Enlist x if not already a list.
Assign to 'a' an unkeyed table which contains the 'x' columns taken from 'y'
Check if the 'x' columns are all of the columns of 'y', if they are not:
Performing 'group 'a' provides a dictionary showing the row indices on which the table can be grouped. Applying this to 'x' will return a dictionary, with key of the columns in 'x', and values of subsets of table 'x' applicable at those indices. So performing a 'flip each' on this results in a table, with key columns of those in 'x', and rows from table 'y' grouped by those columns.
If they are:
It is difficult to figure out in which scenario this applies...
xkey
Set specified columns as primary keys of a table
k){(#x)!.[0!y;();xcols x]}
{
(count x)! .[0!y; (); xcols[x;] ]
}
Re-order the columns of 'y' so those of 'x' are at the start. Key the table on that number of columns.
xlog
Logarithm
k){log[y]%log x}
{
log[y]%log x
}
Self-explanatory.
xprev
Nearby items in a list
k){$[0h>@y;'`rank;y(!#y)-x]}
{
$[0h>type y;
'`rank;
y(til count y)-x
]
}
Make a list of '(y index)-x' and return the values of 'y' at those indices.
xrank
Group by value
k){$[0h>@y;'`rank;_y*x%#y:<<y]}
{
$[0h>type y;
'`rank;
floor y* x%count y:iasc iasc y
]
}
If y is a list:
Convert y to a list of indices which show the order each index would be if the list was sorted.
Divide x by the count of y and multiply the result by y.
Round down the result.