Skip to content

q functions and operators

This page documents the PyKX implementations of a selection of keywords and operators available in q.

The functions listed here are accessible in PyKX as attributes of pykx.q, or as attributes of pykx.QConnection instances. Refer to the q reference card in the q docs for more details about these functions as they are used in a q process. This page documents using them in Python via PyKX.

These functions take and return q objects, which are wrapped in PyKX as pykx.K objects. Any arguments of other types are converted appropriately. Refer to the PyKX wrappers documentation for more information about pykx.K objects.

By Category

Category Elements
Environment getenv, gtime, ltime, setenv
Interpret eval, parse, reval, show, system, value
IO dsave, get, hclose, hcount, hdel, hopen, hsym, load, read0, read1, rload, rsave, save, set
Iterate each, over, peach, prior, scan
Join aj, aj0, ajf, ajf0, asof, ej, ij, ijf, lj, ljf, pj, uj, ujf, wj, wj1
List count, cross, cut, enlist, fills, first, flip, group, inter, last, mcount, next, prev, raze, reverse, rotate, sublist, sv, til, union, vs, where, xprev
Logic all, any
Math abs, acos, asin, atan, avg, avgs, ceiling, cor, cos, cov, deltas, dev, div, ema, exp, floor, inv, log, lsq, mavg, max, maxs, mdev, med, min, mins, mmax, mmin, mmu, mod, msum, neg, prd, prds, rand, ratios, reciprocal, scov, sdev, signum, sin, sqrt, sum, sums, svar, tan, var, wavg, within, wsum, xexp, xlog
Meta attr, null, tables, type, view, views
Query fby
Sort asc, bin, binr, desc, differ, distinct, iasc, idesc, rank, xbar, xrank
Table cols, csv, fkeys, insert, key, keys, meta, ungroup, upsert, xasc, xcol, xcols, xdesc, xgroup, xkey
Text like, lower, ltrim, md5, rtrim, ss, ssr, string, trim, upper
Operators drop, coalesce, fill, take, set_attribute, join, find, enum_extend, roll, deal, dict, enkey, unkey, enumeration, enumerate, pad, cast, tok, compose

Some keywords listed on the q reference card are unavailable in this API:

  • select, exec, update and delete are not q functions, but a part of the q language itself

  • functions that have names which would result in syntax errors in Python, such as not and or

The unavailable functions can still be used in PyKX by executing q code with pykx.q, i.e. pykx.q('not') instead of pykx.q.not. For the qSQL functions (select, exec, update, and delete) use PyKX qSQL.

Environment

getenv

Get the value of an environment variable.

>>> pykx.q.getenv('EDITOR')
pykx.CharVector(q('"nvim"'))

gtime

UTC equivalent of local timestamp.

>>> import datetime
>>> pykx.q.gtime(datetime.datetime.fromisoformat('2022-05-22T12:23:45.123'))
pykx.TimestampAtom(q('2022.05.22D16:23:45.123000000'))

ltime

Local equivalent of UTC timestamp.

>>> import datetime
>>> pykx.q.ltime(datetime.datetime.fromisoformat('2022-05-22T12:23:45.123'))
pykx.TimestampAtom(q('2022.05.22D08:23:45.123000000'))

setenv

Set the value of an environment variable.

>>> pykx.q.setenv('RTMP', b'/home/user/temp')
>>> pykx.q.getenv('RTMP')
pykx.CharVector(q('"/home/user/temp"'))

Interpret

eval

Evaluate parse trees.

>>> pykx.q.eval([pykx.q('+'), 2, 3])
pykx.LongAtom(q('5'))

parse

Parse a char vector into a parse tree, which can be evaluated with pykx.q.eval.

>>> pykx.q.parse(b'{x * x}')
pykx.Lambda(q('{x * x}'))
>>> pykx.q.parse(b'2 + 3')
pykx.List(pykx.q('
+
2
3
'))

reval

Restricted evaluation of a parse tree.

Behaves similar to eval except the evaluation is blocked from modifying values or global state.

>>> pykx.q.reval(pykx.q.parse(b'til 10'))
pykx.LongVector(q('0 1 2 3 4 5 6 7 8 9'))

show

Print the string representation of the given q object.

Note: show bypasses typical Python output redirection. The q function show prints directly to file descriptor 1, so typical Python output redirection methods, e.g. contextlib.redirect_stdout, will not affect it.

>>> pykx.q.show(range(5))
0
1
2
3
4
pykx.Identity(q('::'))

system

Execute a system command.

Where x is a string representing a system command and any parameters to it, executes the command and returns any result.

>>> pykx.q.system(b'pwd')
pykx.List(q('"/home/user"'))

value

Returns the value of x.

Input Type Output Type
dictionary value of the dictionary
symbol atom value of the variable it names
enumeration corresponding symbol vector
string result of evaluating it in current context
list result of evaluating list as a parse tree
projection list: function followed by argument/s
composition list of composed values
derived function argument of the iterator
operator internal code
view list of metadata
lambda structure
file symbol content of datafile
>>> pykx.q.value(pykx.q('`q`w`e!(1 2; 3 4; 5 6)'))
pykx.List(q('
1 2
3 4
5 6
'))

IO

dsave

Write global tables to disk as splayed, enumerated, indexed q tables.

>>> from pathlib import Path
>>> pykx.q['t'] = kx.Table(data={'x': [1, 2, 3], 'y': [10, 20, 30]})
>>> pykx.q.dsave(Path('v'), 't')
pykx.SymbolAtom(q('`t'))

get

Read or memory-map a variable or q data file.

>>> pykx.q['a'] = 10
>>> pykx.q.get('a')
pykx.LongAtom(q('10'))

hclose

Where x is a connection handle, closes the connection, and destroys the handle.

>>> pykx.q.hclose(pykx.q('3i'))

hcount

Size of a file in bytes.

>>> pykx.q.hcount('example.txt')
pykx.LongAtom(q('11'))

hdel

Where x is a file symbol atom, deletes the file or folder (if empty), and returns x.

>>> pykx.q.hdel('example.txt')

hopen

Open a connection to a file or process.

>>> pykx.q.hopen('example.txt')
pykx.IntAtom(q('3i'))

hsym

Convert symbols to handle symbols, which can be used for I/O as file descriptors or handles.

>>> pykx.q.hsym('10.43.23.197')
pykx.SymbolAtom(q('`:10.43.23.197'))

load

Load binary data from a file.

>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]], columns=['x', 'y'])
>>> pykx.q('t')
pykx.Table(pykx.q('
x y
----
1 10
2 20
3 30
'))
>>> pykx.q.save('t') # Save t to disk
pykx.SymbolAtom(pykx.q('`:t'))
>>> pykx.q('delete t from `.') # Delete t from memory
pykx.SymbolAtom(pykx.q('`.'))
>>> pykx.q('t') # t is not longer defined
Traceback (most recent call last):
pykx.exceptions.QError: t
>>> pykx.q.load('t') # Load t from disk
pykx.SymbolAtom(pykx.q('`t'))
>>> pykx.q('t')
pykx.Table(pykx.q('
x y
----
1 10
2 20
3 30
'))

read0

Read text from a file or process handle.

>>> pykx.q.read0('example.txt')
pykx.List(q('
"Hello"
"World"
'))

read1

Read bytes from a file or named pipe.

>>> pykx.q.read1('example.txt')
pykx.ByteVector(q('0x48656c6c6f0a576f726c64'))

rload

Load a splayed table from a directory.

>>> pykx.q.rload('t')
>>> pykx.q('t')
pykx.Table(q('
x y
----
1 10
2 20
3 30
'))

rsave

Write a table splayed to a directory.

>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]])
>>> pykx.q.rsave('t')
pykx.SymbolAtom(q('`:t/'))

save

Write global data to file or splayed to a directory.

>>> pykx.q['t'] = pykx.Table([[1, 10], [2, 20], [3, 30]])
>>> pykx.q.save('t')
pykx.SymbolAtom(q('`:t'))

set

Assign a value to a global variable.

Persist an object as a file or directory.

Types Result
pykx.q.set(nam, y) set global nam to y
pykx.q.set(fil, y) write y to a file
pykx.q.set(dir, y) splay y to a directory
pykx.q.set([fil, lbs, alg, lvl], y) write y to a file, compressed
pykx.q.set([dir, lbs, alg, lvl], y) splay y to a directory, compressed
pykx.q.set([dir, dic], y) splay y to a directory, compressed

Where

Abbreviation K type Explanation
alg integer atom compression algorithm
dic dictionary compression specifications
dir filesymbol directory in the filesystem
fil filesymbol file in the filesystem
lbs integer atom logical block size
lvl integer atom compression level
nam symbol atom valid q name
t table
y (any) any q object

Compression parameters alg, lbs, and lvl

Compression specification dictionary

>>> pykx.q.set('a', 42)
pykx.SymbolAtom(q('`a'))
>>> pykx.q('a')
pykx.LongAtom(q('42'))

Iterate

each

Iterate over list and apply a function to each element.

>>> pykx.q.each(pykx.q.count, [b'Tis', b'but', b'a', b'scratch'])
pykx.LongVector(q('3 3 1 7'))
>>> pykx.q.each(pykx.q.sums, [[2, 3, 4], [[5, 6], [7, 8]], [9, 10, 11, 12]])
pykx.List(q('
2 5 9
((5;6);12 14)
9 19 30 42
'))

over

The keywords over and scan are covers for the accumulating iterators, Over and Scan. It is good style to use over and scan with unary and binary values.

Just as with Over and Scan, over and scan share the same syntax and perform the same computation; but while scan returns the result of each evaluation, over returns only the last.

>>> pykx.q.over(pykx.q('*'), [1, 2, 3, 4, 5])
pykx.LongAtom(q('120'))

peach

each and peach perform the same computation and return the same result, but peach will parallelize the work across available threads.

>>> pykx.q.peach(pykx.q.count, [b'Tis', b'but', b'a', b'scratch'])
pykx.LongVector(q('3 3 1 7'))
>>> pykx.q.peach(pykx.q.sums, [[2, 3, 4], [[5, 6], [7, 8]], [9, 10, 11, 12]])
pykx.List(q('
2 5 9
((5;6);12 14)
9 19 30 42
'))

prior

Applies a function to each item of x and the item preceding it, and returns a result of the same length.

>>> pykx.q.prior(pykx.q('+'), [1, 2, 3, 4, 5])
pykx.LongVector(pykx.q('1 3 5 7 9'))
>>> pykx.q.prior(lambda x, y: x + y, pykx.LongVector([1, 2, 3, 4, 5]))
pykx.LongVector(pykx.q('0N 3 5 7 9'))

scan

The keywords over and scan are covers for the accumulating iterators, Over and Scan. It is good style to use over and scan with unary and binary values.

Just as with Over and Scan, over and scan share the same syntax and perform the same computation; but while scan returns the result of each evaluation, over returns only the last.

>>> pykx.q.scan(pykx.q('+'), [1, 2, 3, 4, 5])
pykx.LongVector(q('1 3 6 10 15'))

Join

aj

Performs an as-of join across temporal columns in tables. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.

The resulting time column is the value of the boundary used in the first table.

>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
...    'time': np.array([36061, 36063, 36064], dtype='timedelta64[s]'),
...    'sym': ['msft', 'ibm', 'ge'], 'qty': [100, 200, 150]
... })
>>> df2 = pd.DataFrame({
...     'time': np.array([36060, 36060, 36060, 36062], dtype='timedelta64[s]'),
...     'sym': ['ibm', 'msft', 'msft', 'ibm'], 'qty': [100, 99, 101, 98]
... })
>>> pykx.q.aj(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time                 sym  qty
-----------------------------
0D10:01:01.000000000 msft 101
0D10:01:03.000000000 ibm  98
0D10:01:04.000000000 ge   150
'))

aj0

Performs an as-of join across temporal columns in tables. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.

The resulting time column is the actual time of the last value in the second table.

>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
...     'time': np.array([36061, 36063, 36064], dtype='timedelta64[s]'),
...     'sym': ['msft', 'ibm', 'ge'], 'qty': [100, 200, 150]
... })
>>> df2 = pd.DataFrame({
...     'time': np.array([36060, 36060, 36060, 36062], dtype='timedelta64[s]'),
...     'sym': ['ibm', 'msft', 'msft', 'ibm'], 'qty': [100, 99, 101, 98]
... })
>>> pykx.q.aj0(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time                 sym  qty
-----------------------------
0D10:01:00.000000000 msft 101
0D10:01:02.000000000 ibm  98
0D10:01:04.000000000 ge   150
'))

ajf

Performs an as-of join across temporal columns in tables with null values being filled. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.

The resulting time column is the value of the boundary used in the first table.

>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
...     'time': np.array([1, 1], dtype='timedelta64[s]'),
...     'sym': ['a', 'b'],
...     'p': pykx.LongVector([0, 1]),
...     'n': ['r', 's']
... })
>>> df2 = pd.DataFrame({
...     'time': np.array([1, 1], dtype='timedelta64[s]'),
...     'sym':['a', 'b'],
...     'p': pykx.q('1 0N')
... })
>>> pykx.q.ajf(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time                 sym p n
----------------------------
0D00:00:01.000000000 a   1 r
0D00:00:01.000000000 b   1 s
'))

ajf0

Performs an as-of join across temporal columns in tables with null values being filled. Returns a table with records from the left-join of the first table and the second table. For each record in the first table, it is matched with the second table over the columns specified in the first input parameter and if there is a match the most recent match will be joined to the record.

The resulting time column is the actual time of the last value in the second table.

>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
...     'time': np.array([1, 1], dtype='timedelta64[s]'),
...     'sym':['a', 'b'],
...     'p': pykx.LongVector([0, 1]),
...     'n': ['r', 's']
... })
>>> df2 = pd.DataFrame({
...     'time': np.array([1, 1], dtype='timedelta64[s]'),
...     'sym': ['a', 'b'],
...     'p': pykx.q('1 0N')
... })
>>> pykx.q.ajf0(pykx.SymbolVector(['sym', 'time']), df1, df2)
pykx.Table(q('
time                 sym p n
----------------------------
0D00:00:01.000000000 a   1 r
0D00:00:01.000000000 b   1 s
'))

asof

Performs an as-of join across temporal columns in tables. The last column the second table must be temporal and correspond to a column in the first table argument. The return is the data from the first table is the last time that is less than or equal to the time in the second table per key. The time column will be removed from the output.

>>> import pandas as pd
>>> import numpy as np
>>> df1 = pd.DataFrame({
...     'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
...     'sym': ['a', 'a', 'b', 'b'], 'p': pykx.LongVector([2, 4, 6, 8])})
>>> df2 = pd.DataFrame({'sym':['b'], 'time': np.array([3], dtype='timedelta64[s]')})
>>> pykx.q.asof(df1, df2)
pykx.Table(q('
p
-
6
'))

ej

Equi join. The result has one combined record for each row in the second table that matches the first table on the columns specified in the first function parameter.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['a', 'a', 'b', 'a', 'c', 'b', 'c', 'a'], 'p': pykx.LongVector([2, 4, 6, 8, 1, 3, 5, 7])})
>>> df2 = pd.DataFrame({'sym':['a', 'b'], 'w': ['alpha', 'beta']})
>>> pykx.q.ej('sym', df1, df2)
pykx.Table(q('
sym p w
-----------
a   2 alpha
a   4 alpha
b   6 beta
a   8 alpha
b   3 beta
a   7 alpha
'))

ij

Inner join. The result has one combined record for each row in the first table that matches the second table on the columns specified in the first function parameter.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df2 = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym  p
------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
'))
>>> df2
pykx.KeyedTable(q('
sym | ex  MC
----| --------
IBM | N   1000
MSFT| CME 250
'))
>>> pykx.q.ij(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7 N   1000
IBM  2 N   1000
MSFT 5 CME 250
'))

ijf

Inner join nulls filled. The result has one combined record for each row in the first table that matches the second table on the columns specified in the first function parameter.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym  p
------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
'))
>>> df2
pykx.KeyedTable(q('
sym | ex  MC
----| --------
IBM | N   1000
MSFT| CME 250
'))
>>> pykx.q.ijf(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7 N   1000
IBM  2 N   1000
MSFT 5 CME 250
'))

lj

Left join. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if no value is present in the second table the record will contain null values in the place of the columns of the second table.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df2)
pykx.Table(q('
sym  p
------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
'))
>>> df1
pykx.KeyedTable(q('
sym | ex  MC
----| --------
IBM | N   1000
MSFT| CME 250
'))
>>> pykx.q.lj(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7 N   1000
FDP  8
FDP  6
FDP  5
IBM  2 N   1000
MSFT 5 CME 250
'))

ljf

Left join nulls filled. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if no value is present in the second table the record will contain null values in the place of the columns of the second table.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> b = pykx.q.xkey('sym', df2)
>>> pykx.Table(df1)
pykx.Table(q('
sym  p
------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
'))
>>> df1
pykx.KeyedTable(q('
sym | ex  MC
----| --------
IBM | N   1000
MSFT| CME 250
'))
>>> pykx.q.ljf(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7 N   1000
FDP  8
FDP  6
FDP  5
IBM  2 N   1000
MSFT 5 CME 250
'))

pj

Plus join. For each record in the first table, the result has one record with the columns of second table joined to columns of the first using the primary keys of the second table, if a value is present it is added to the columns of the first table, if no value is present the columns are left unchanged and new columns are set to 0.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'a': pykx.LongVector([1, 2, 3]), 'b':['x', 'y', 'z'], 'c': pykx.LongVector([10, 20, 30])})
>>> pykx.Table(df1)
pykx.Table(q('
a b c
------
1 x 10
2 y 20
3 z 30
'))
>>> df2 = pd.DataFrame({
...     'a': pykx.LongVector([1, 3]),
...     'b':['x', 'z'],
...     'c': pykx.LongVector([1, 2]),
...     'd': pykx.LongVector([10, 20])
... })
>>> df2 = pykx.q.xkey(pykx.SymbolVector(['a', 'b']), df2)
pykx.KeyedTable(q('
a b| c d
---| ----
1 x| 1 10
3 z| 2 20
'))
>>> pykx.q.pj(df1, df2)
pykx.Table(q('
a b c  d
---------
1 x 11 10
2 y 20 0
3 z 32 20
'))

uj

Union join. Where the first table and the second table are both keyed or both unkeyed tables, returns the union of the columns, filled with nulls where necessary. If the tables have matching key columns then the records in the second table will be used to update the first table, if the tables are not keyed then the records from the second table will be joined onto the end of the first table.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df1
    sym  p
0   IBM  7
1   FDP  8
2   FDP  6
3   FDP  5
4   IBM  2
5  MSFT  5
>>> df2
    sym   ex    MC
0   IBM    N  1000
1  MSFT  CME   250
>>> pykx.q.uj(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
IBM    N   1000
MSFT   CME 250
'))

ujf

Union join nulls filled. Where the first table and the second table are both keyed or both unkeyed tables, returns the union of the columns, filled with nulls where necessary. If the tables have matching key columns then the records in the second table will be used to update the first table, if the tables are not keyed then the records from the second table will be joined onto the end of the first table.

>>> import pandas as pd
>>> df1 = pd.DataFrame({'sym':['IBM', 'FDP', 'FDP', 'FDP', 'IBM', 'MSFT'], 'p': pykx.LongVector([7, 8, 6, 5, 2, 5])})
>>> df2 = pd.DataFrame({'sym':['IBM', 'MSFT'], 'ex': ['N', 'CME'], 'MC': pykx.LongVector([1000, 250])})
>>> df1
    sym  p
0   IBM  7
1   FDP  8
2   FDP  6
3   FDP  5
4   IBM  2
5  MSFT  5
>>> df2
    sym   ex    MC
0   IBM    N  1000
1  MSFT  CME   250
>>> pykx.q.ujf(df1, df2)
pykx.Table(q('
sym  p ex  MC
---------------
IBM  7
FDP  8
FDP  6
FDP  5
IBM  2
MSFT 5
IBM    N   1000
MSFT   CME 250
'))

wj

Window join. Returns for each record in the table, a record with additional columns c0 and c1, which contain the results of the aggregation functions applied to values over the matching intervals defined in the first parameter of the function.

>>> import pandas as pd
>>> import numpy as np
>>> pykx.q('t: ([]sym:3#`ibm;time:10:01:01 10:01:04 10:01:08;price:100 101 105)')
pykx.Table(pykx.q('
sym time     price
------------------
ibm 10:01:01 100
ibm 10:01:04 101
ibm 10:01:08 105
'))
>>> df_t = pd.DataFrame({
        'sym': ['ibm', 'ibm', 'ibm'],
        'time': np.array([36061, 36064, 36068], dtype='timedelta64[s]'),
        'price': pykx.LongVector([100, 101, 105])
    })
   sym            time  price
0  ibm 0 days 10:01:01    100
1  ibm 0 days 10:01:04    101
2  ibm 0 days 10:01:08    105
>>> pykx.q('q:([]sym:`ibm; time:10:01:01+til 9; ask: (101 103 103 104 104 107 108 107 108); bid: (98 99 102 103 103 104 106 106 107))')
pykx.Table(pykx.q('
sym time     ask bid
--------------------
ibm 10:01:01 101 98
ibm 10:01:02 103 99
ibm 10:01:03 103 102
ibm 10:01:04 104 103
ibm 10:01:05 104 103
ibm 10:01:06 107 104
ibm 10:01:07 108 106
ibm 10:01:08 107 106
ibm 10:01:09 108 107
'))
>>> f = pykx.SymbolVector(['sym', 'time'])
>>> w = pykx.q('-2 1+\:t.time')
>>> pykx.q.wj(w, f, df_t, pykx.q('(q;(max;`ask);(min;`bid))'))
pykx.Table(pykx.q('
sym time     price ask bid
--------------------------
ibm 10:01:01 100   103 98
ibm 10:01:04 101   104 99
ibm 10:01:08 105   108 104
'))

wj1

Window join. Returns for each record in the table, a record with additional columns c0 and c1, which contain the results of the aggregation functions applied to values over the matching intervals defined in the first parameter of the function.

>>> import pandas as pd
>>> import numpy as np
>>> pykx.q('t: ([]sym:3#`ibm;time:10:01:01 10:01:04 10:01:08;price:100 101 105)')
pykx.Table(pykx.q('
sym time     price
------------------
ibm 10:01:01 100
ibm 10:01:04 101
ibm 10:01:08 105
'))
>>> df_t = pd.DataFrame({
...     'sym': ['ibm', 'ibm', 'ibm'],
...     'time': np.array([36061, 36064, 36068], dtype='timedelta64[s]'),
...     'price': pykx.LongVector([100, 101, 105])
... })
   sym            time  price
0  ibm 0 days 10:01:01    100
1  ibm 0 days 10:01:04    101
2  ibm 0 days 10:01:08    105
>>> pykx.q('q:([]sym:`ibm; time:10:01:01+til 9; ask: (101 103 103 104 104 107 108 107 108); bid: (98 99 102 103 103 104 106 106 107))')
pykx.Table(pykx.q('
sym time     ask bid
--------------------
ibm 10:01:01 101 98
ibm 10:01:02 103 99
ibm 10:01:03 103 102
ibm 10:01:04 104 103
ibm 10:01:05 104 103
ibm 10:01:06 107 104
ibm 10:01:07 108 106
ibm 10:01:08 107 106
ibm 10:01:09 108 107
'))
>>> f = pykx.SymbolVector(['sym', 'time'])
>>> w = pykx.q('-2 1+\:t.time')
>>> pykx.q.wj(w, f, df_t, pykx.q('(q;(max;`ask);(min;`bid))'))
pykx.Table(pykx.q('
sym time     price ask bid
--------------------------
ibm 10:01:01 100   103 98
ibm 10:01:04 101   104 99
ibm 10:01:08 105   108 104
'))

List

count

Count the items of a list or dictionary.

>>> pykx.q.count([1, 2, 3])
pykx.LongAtom(q('3'))

cross

Returns all possible combinations of x and y.

>>> pykx.q.cross([1, 2, 3], [4, 5, 6])
pykx.List(q('
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
'))

cut

Cut a list or table into sub-arrays.

>>> pykx.q.cut(3, range(10))
pykx.List(q('
0 1 2
3 4 5
6 7 8
,9
'))

enlist

Returns a list with its arguments as items.

>>> pykx.q.enlist(1, 2, 3, 4)
pykx.LongVector(q('1 2 3 4'))

fills

Replace nulls with preceding non-nulls.

>>> a = pykx.q('0N 1 2 0N 0N 2 3 4 5 0N 4')
>>> pykx.q.fills(a)
pykx.LongVector(q('0N 1 2 2 2 2 3 4 5 5 4'))

first

First item of a list

>>> pykx.q.first([1, 2, 3, 4, 5])
pykx.LongAtom(q('1'))

flip

Returns x transposed, where x may be a list of lists, a dictionary or a table.

>>> pykx.q.flip([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
pykx.List(q('
1 6
2 7
3 8
4 9
5 10
'))

group

Returns a dictionary in which the keys are the distinct items of x, and the values the indexes where the distinct items occur.

The order of the keys is the order in which they appear in x.

>>> pykx.q.group(b'mississippi')
pykx.Dictionary(q('
m| ,0
i| 1 4 7 10
s| 2 3 5 6
p| 8 9
'))

inter

Intersection of two lists or dictionaries.

>>> pykx.q.inter([1, 2, 3], [2, 3, 4])
pykx.LongVector(q('2 3'))

last

Last item of a list

>>> pykx.q.last([1, 2, 3])
pykx.LongAtom(q('3'))

mcount

Returns the x-item moving counts of the non-null items of y. The first x items of the result are the counts so far, and thereafter the result is the moving count.

>>> pykx.q.mcount(3, pykx.q('1 2 3 4 5 0N 6 7 8'))
pykx.IntVector(q('1 2 3 3 3 2 2 2 3i'))

next

Next items in a list.

>>> pykx.q.next([1, 2, 3, 4])
pykx.LongVector(q('2 3 4 0N'))

prev

Immediately preceding items in a list.

>>> pykx.q.prev([1, 2, 3, 4])
pykx.LongVector(q('0N 1 2 3'))

raze

Return the items of x joined, collapsing one level of nesting.

>>> pykx.q.raze([[1, 2], [3, 4]])
pykx.LongVector(q('1 2 3 4'))

reverse

Reverse the order of items of a list or dictionary.

>>> pykx.q.reverse([1, 2, 3, 4, 5])
pykx.List(q('
5
4
3
2
1
'))

rotate

Shift the items of a list to the left or right.

>>> pykx.q.rotate(2, [1, 2, 3, 4, 5])
pykx.LongVector(q('3 4 5 1 2'))

sublist

Select a sublist of a list.

>>> pykx.q.sublist(2, [1, 2, 3, 4, 5])
pykx.LongVector(q('1 2'))

sv

"Scalar from vector"

  • join strings, symbols, or filepath elements
  • decode a vector to an atom
>>> pykx.q.sv(10, [1, 2, 3, 4])
pykx.LongAtom(q('1234'))

til

First x natural numbers.

>>> pykx.q.til(10)
pykx.LongVector(q('0 1 2 3 4 5 6 7 8 9'))

union

Union of two lists.

>>> pykx.q.union([1, 2, 3, 3, 5], [2, 4, 6, 8])
pykx.LongVector(q('1 2 3 5 4 6 8'))

vs

"Vector from scalar"

  • partition a symbol, string, or bytestream
  • encode a vector from an atom, or a matrix from a vector
>>> pykx.q.vs(b',', b'one,two,three')
pykx.List(q('
"one"
"two"
"three"
'))

where

Copies of indexes of a list or keys of a dictionary.

>>> pykx.q.where(pykx.BooleanVector([True, False, True, True, False]))
pykx.LongVector(q('0 2 3'))
>>> pykx.q.where(pykx.q('1 0 0 1 0 1 1'))
pykx.LongVector(q('0 3 5 6'))

xprev

Nearby items in a list.

>>> pykx.q.xprev(2, [1, 2, 3, 4, 5, 6])
pykx.LongVector(q('0N 0N 1 2 3 4'))

There is no xnext function, but xprev with a negative number as its first argument can achieve this.

>>> pykx.q.xprev(-2, [1, 2, 3, 4, 5, 6])
pykx.LongVector(q('3 4 5 6 0N 0N'))

Logic

all

Everything is true.

>>> pykx.q.all([True, True, True, True])
pykx.BooleanAtom(q('1b'))
>>> pykx.q.all([True, True, False, True])
pykx.BooleanAtom(q('0b'))

any

Something is true.

>>> pykx.q.any([False, False, True, False])
pykx.BooleanAtom(q('1b'))
>>> pykx.q.any([False, False])
pykx.BooleanAtom(q('0b'))

Math

abs

Where x is a numeric or temporal, returns the absolute value of x. Null is returned if x is null.

>>> pykx.q.abs(-5)
pykx.LongAtom(q('5'))

acos

The arccosine of x; that is, the value whose cosine is x. The result is in radians and lies between 0 and π.

>>> pykx.q.acos(0.5)
pykx.FloatAtom(q('1.047198'))

asin

The arcsine of x; that is, the value whose sine is x. The result is in radians and lies between -π / 2 and π / 2. (The range is approximate due to rounding errors). Null is returned if the argument is not between -1 and 1.

>>> pykx.q.asin(0.5)
pykx.FloatAtom(q('0.5235988'))

atan

The arctangent of x; that is, the value whose tangent is x. The result is in radians and lies between -π / 2 and π / 2.

>>> pykx.q.atan(0.5)
pykx.FloatAtom(q('0.4636476'))

avg

Arithmetic mean.

>>> pykx.q.avg([1, 2, 3, 4, 7])
pykx.FloatAtom(q('3.4'))

avgs

Running mean.

>>> pykx.q.avgs([1, 2, 3, 4, 7])
pykx.FloatVector(q('1 1.5 2 2.5 3.4'))

ceiling

Round up.

>>> pykx.q.ceiling([-2.7, -1.1, 0, 1.1, 2.7])
pykx.LongVector(q('-2 -1 0 2 3'))

cor

Correlation.

>>> pykx.q.cor(pykx.LongVector([29, 10, 54]), pykx.LongVector([1, 3, 9]))
pykx.FloatAtom(q('0.7727746'))

cos

The cosine of x, taken to be in radians. The result is between -1 and 1, or null if the argument is null or infinity.

>>> pykx.q.cos(0.2)
pykx.FloatAtom(q('0.9800666'))

cov

Where x and y are conforming numeric lists returns their covariance as a floating-point number. Applies to all numeric data types and signals an error with temporal types, char and sym.

>>> pykx.q.cov(pykx.LongVector([29, 10, 54]), pykx.LongVector([1, 3, 9]))
pykx.FloatAtom(q('47.33333'))

deltas

Where x is a numeric or temporal vector, returns differences between consecutive pairs of its items.

>>> pykx.q.deltas(pykx.LongVector([1, 4, 9, 16]))
pykx.LongVector(q('1 3 5 7'))

dev

Standard deviation.

>>> pykx.q.dev(pykx.LongVector([10, 343, 232, 55]))
pykx.FloatAtom(q('134.3484'))

div

Integer division.

>>> pykx.q.div(7, 3)
pykx.LongAtom(q('2'))

ema

The cosine of x, taken to be in radians. The result is between -1 and 1, or null if the argument is null or infinity.

>>> pykx.q.ema(0.5, [1, 2, 3, 4, 5])
pykx.FloatVector(q('1 1.5 2.25 3.125 4.0625'))

exp

Raise e to a power.

>>> pykx.q.exp(1)
pykx.FloatAtom(q('2.718282'))

floor

Round down.

>>> pykx.q.floor([-2.7, -1.1, 0, 1.1, 2.7])
pykx.LongVector(q('-3 -2 0 1 2'))

inv

Matrix inverse.

>>> a = pykx.q('3 3# 2 4 8 3 5 6 0 7 1f')
pykx.List(q('
2 4 8
3 5 6
0 7 1
'))
>>> pykx.q.inv(a)
pykx.List(q('
-0.4512195  0.6341463  -0.195122
-0.03658537 0.02439024 0.1463415
0.2560976   -0.1707317 -0.02439024
'))

log

Natural logarithm.

>>> pykx.q.log([1, 2, 3])
pykx.FloatVector(q('0 0.6931472 1.098612'))

lsq

Least squares, matrix divide.

>>> a = pykx.q('1f+3 4#til 12')
pykx.List(q('
1 2  3  4
5 6  7  8
9 10 11 12
'))
>>> b = pykx.q('4 4#2 7 -2 5 5 3 6 1 -2 5 2 7 5 0 3 4f')
pykx.List(q('
2  7 -2 5
5  3 6  1
-2 5 2  7
5  0 3  4
'))
>>> pykx.q.lsq(a, b)
pykx.List(q('
-0.1233333 0.16      0.4766667 0.28
0.07666667 0.6933333 0.6766667 0.5466667
0.2766667  1.226667  0.8766667 0.8133333
'))

mavg

Moving averages.

>>> pykx.q.mavg(3, [1, 2, 3, 5, 7, 10])
pykx.FloatVector(q('1 1.5 2 3.333333 5 7.333333'))

max

Maximum.

>>> pykx.q.max([0, 7, 2, 4 , 1, 3])
pykx.LongAtom(q('7'))

maxs

Maximums.

>>> pykx.q.maxs([1, 2, 5, 4, 7, 1, 2])
pykx.LongVector(q('1 2 5 5 7 7 7'))

mdev

Moving deviations.

>>> pykx.q.mdev(3, [1, 2, 5, 4, 7, 1, 2])
pykx.FloatVector(q('0 0.5 1.699673 1.247219 1.247219 2.44949 2.624669'))

med

Median.

>>> pykx.q.med([1, 2, 3, 4, 4, 1, 2, 4, 5])
pykx.FloatAtom(q('3f'))

min

Minimum.

>>> pykx.q.min([7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongAtom(q('1'))

mins

Minimums.

>>> pykx.q.mins([7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongVector(q('7 5 2 2 2 2 1 1'))

mmax

Moving maximums.

>>> pykx.q.mmax(4, [7, 5, 2, 4, 6, 5, 1, 4])
pykx.LongVector(q('7 7 7 7 6 6 6 6'))

mmin

Moving minimums.

>>> pykx.q.mmin(4, pykx.LongVector([7, 5, 2, 4, 6, 5, 1, 4]))
pykx.LongVector(q('7 5 2 2 2 2 1 1'))

mmu

Matrix multiply, dot product.

>>> a = pykx.q('2 4#2 4 8 3 5 6 0 7f')
>>> a
pykx.List(q('
2 4 8 3
5 6 0 7
'))
>>> b = pykx.q('4 3#"f"$til 12')
>>> b
pykx.List(q('
0 1  2
3 4  5
6 7  8
9 10 11
'))
>>> pykx.q.mmu(a, b)
pykx.List(q('
87 104 121
81 99  117
'))

mod

Modulus.

>>> pykx.q.mod([1, 2, 3, 4, 5, 6, 7], 4)
pykx.LongVector(q('1 2 3 0 1 2 3'))

msum

Moving sums.

>>> pykx.q.msum(3, [1, 2, 3, 4, 5, 6, 7])
pykx.LongVector(q('1 3 6 9 12 15 18'))

neg

Negate.

>>> pykx.q.neg([2, 0, -1, 3, -5])
pykx.LongVector(q('-2 0 1 -3 5'))

prd

Product.

>>> pykx.q.prd([1, 2, 3, 4, 5])
pykx.LongAtom(q('120'))

prds

Cumulative products.

>>> pykx.q.prds([1, 2, 3, 4, 5])
pykx.LongVector(q('1 2 6 24 120'))

rand

Pick randomly.

>>> pykx.q.rand([1, 2, 3, 4, 5])
pykx.LongAtom(q('2'))

ratios

Ratios between items.

>>> pykx.q.ratios([1, 2, 3, 4, 5])
pykx.FloatVector(q('0n 2 1.5 1.333333 1.25'))

reciprocal

Reciprocal of a number.

>>> pykx.q.reciprocal([1, 0, 3])
pykx.FloatVector(q('1 0w 0.3333333'))

scov

Sample covariance.

>>> pykx.q.scov(pykx.LongVector([2, 3, 5, 7]), pykx.LongVector([4, 3, 0, 2]))
pykx.FloatAtom(q('-2.416667'))

sdev

Sample standard deviation.

>>> pykx.q.sdev(pykx.LongVector([10, 343, 232, 55]))
pykx.FloatAtom(q('155.1322'))

signum

Where x (or its underlying value for temporals) is

  • null or negative, returns -1i
  • zero, returns 0i
  • positive, returns 1i
>>> pykx.q.signum([-2, 0, 1, 3])
pykx.IntVector(q('-1 0 1 1i'))

sin

Sine.

>>> pykx.q.sin(0.5)
pykx.FloatAtom(q('0.4794255'))

sqrt

Square root.

>>> pykx.q.sqrt([-1, 0, 25, 50])
pykx.FloatVector(q('0n 0 5 7.071068'))

sum

Total.

>>> pykx.q.sum(pykx.LongVector([2, 3, 5, 7]))
pykx.LongAtom(q('17'))

sums

Cumulative total.

>>> pykx.q.sums(pykx.LongVector([2, 3, 5, 7]))
pykx.LongVector(q('2 5 10 17'))

svar

Sample variance.

>>> pykx.q.svar(pykx.LongVector([2, 3, 5, 7]))
pykx.FloatAtom(q('4.916667'))

tan

Tangent.

>>> pykx.q.tan(0.5)
pykx.FloatAtom(q('0.5463025'))

var

Variance.

>>> pykx.q.var(pykx.LongVector([2, 3, 5, 7]))
pykx.FloatAtom(q('3.6875'))

wavg

Weighted average.

>>> pykx.q.wavg([2, 3, 4], [1, 2 ,4])
pykx.FloatAtom(q('2.666667'))

within

Check bounds.

>>> pykx.q.within([1, 3, 10, 6, 4], [2, 6])
pykx.BooleanVector(q('01011b'))

wsum

Weighted sum.

>>> pykx.q.wsum([2, 3, 4], [1, 2, 4]) # equivalent to 2 * 1 + 3 * 2 + 4 * 4
pykx.LongAtom(q('24'))

xexp

Raise x to a power.

>>> pykx.q.xexp(2, 8)
pykx.FloatAtom(q('256f'))

xlog

Logarithm base x.

>>> pykx.q.xlog(2, 8)
pykx.FloatAtom(q('3f'))

Meta

attr

Attributes of an object, returns a Symbol Atom or Vector.

The possible attributes are:

code attribute
s sorted
u unique (hash table)
p partitioned (grouped)
g true index (dynamic attribute): enables constant time update and access for real-time tables
>>> pykx.q.attr([1,2,3])
pykx.SymbolAtom(q('`'))
>>> pykx.q.attr(pykx.q('asc 1 2 3'))
pykx.SymbolAtom(q('`s'))

null

Is null.

>>> pykx.q.null(1)
pykx.BooleanAtom(q('0b'))
>>> pykx.q.null(float('NaN'))
pykx.BooleanAtom(q('1b'))
>>> pykx.q.null(None)
pykx.BooleanAtom(q('1b'))

tables

List of tables in a namespace.

>>> pykx.q('exampleTable: ([] a: til 10; b: 10?10)')
pykx.Identity(pykx.q('::'))
>>> pykx.q('exampleTable: ([] a: til 10; b: 10?10)')
pykx.Table(q('
a b
---
0 8
1 1
2 9
3 5
4 4
5 6
6 6
7 1
8 8
9 5
'))
>>> pykx.q.tables('.')
pykx.SymbolVector(q(',`exampleTable'))

type

Underlying k type of an object.

>>> pykx.q.type(1)
pykx.ShortAtom(q('-7h'))
>>> pykx.q.type([1, 2, 3])
pykx.ShortAtom(q('0h'))
>>> pykx.q.type(pykx.LongVector([1, 2, 3]))
pykx.ShortAtom(q('7h'))

view

Expression defining a view.

>>> pykx.q('v::2+a*3')
>>> pykx.q('a:5')
>>> pykx.q('v')
pykx.LongAtom(q('17'))
>>> pykx.q.view('v')
pykx.CharVector(q('"2+a*3"'))

views

List views defined in the default namespace.

>>> pykx.q('v::2+a*3')
>>> pykx.q('a:5')
>>> pykx.q('v')
pykx.LongAtom(q('17'))
>>> pykx.q.views()
pykx.SymbolVector(q(',`v'))

Queries

fby

Apply an aggregate to groups.

>>> d = pykx.q('data: 10?10')
pykx.LongVector(pykx.q('4 9 2 7 0 1 9 2 1 8'))
>>> group = pykx.SymbolVector(['a', 'b', 'a', 'b', 'c', 'd', 'c', 'd', 'd', 'c'])
pykx.SymbolVector(pykx.q('`a`b`a`b`c`d`c`d`d`c'))
>>> >>> pykx.q.fby(pykx.q('(sum; data)'), group)
pykx.LongVector(pykx.q('6 16 6 16 17 4 17 4 4 17'))

Sort

asc

Ascending sort.

>>> pykx.q.asc([4, 2, 5, 1, 0])
pykx.LongVector(q('`s#0 1 2 4 5'))

bin

Binary search.

>>> pykx.q.bin([0, 2, 4, 6, 8, 10], 5)
pykx.LongAtom(q('2'))
>>> pykx.q.bin([0, 2, 4, 6, 8, 10], [-10, 0, 4, 5, 6, 20])
pykx.LongVector(q('-1 0 2 2 3 5'))

binr

Binary search right.

>>> pykx.q.binr([0, 2, 4, 6, 8, 10], 5)
pykx.LongAtom(q('3'))
>>> pykx.q.binr([0, 2, 4, 6, 8, 10], [-10, 0, 4, 5, 6, 20])
pykx.LongVector(q('0 0 2 3 3 6'))

desc

Descending sort.

>>> pykx.q.desc([4, 2, 5, 1, 0])
pykx.LongVector(q('5 4 2 1 0'))

differ

Find where list items change value.

>>> pykx.q.differ([1, 1, 2, 3, 4, 4])
pykx.BooleanVector(q('101110b'))

distinct

Unique items of a list.

>>> pykx.q.distinct([1, 3, 1, 4, 5, 1, 2, 3])
pykx.LongVector(q('1 3 4 5 2'))

iasc

Ascending grade.

>>> pykx.q.iasc([4, 2, 5, 1, 0])
pykx.LongVector(q('4 3 1 0 2'))

idesc

Descending grade.

>>> pykx.q.idesc([4, 2, 5, 1, 0])
pykx.LongVector(q('2 0 1 3 4'))

rank

Position in the sorted list.

Where x is a list or dictionary, returns for each item in x the index of where it would occur in the sorted list or dictionary.

>>> pykx.q.rank([4, 2, 5, 1, 0])
pykx.LongVector(q('3 2 4 1 0'))
>>> pykx.q.rank({'c': 3, 'a': 4, 'b': 1})
pykx.LongVector(q('2 0 1'))

xbar

Round y down to the nearest multiple of x.

>>> pykx.q.xbar(5, 3)
pykx.LongAtom(q('0'))
>>> pykx.q.xbar(5, 5)
pykx.LongAtom(q('5'))
>>> pykx.q.xbar(5, 7)
pykx.LongAtom(q('5'))
>>> pykx.q.xbar(3, range(16))
pykx.LongVector(q('0 0 0 3 3 3 6 6 6 9 9 9 12 12 12 15'))

xrank

Group by value.

>>> pykx.q.xrank(3, range(6))
pykx.LongVector(q('0 0 1 1 2 2'))
>>> pykx.q.xrank(4, range(9))
pykx.LongVector(q('0 0 0 1 1 2 2 3 3'))

Table

cols

Column names of a table.

>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
...     'time': numpy.array([1, 2, 3, 4], dtype='timedelta64[s]'),
...     'sym':['a', 'a', 'b', 'b'],
...     'p': pykx.LongVector([2, 4, 6, 8])
...  })
>>> pykx.q.cols(df)
pykx.SymbolVector(q('`time`sym`p'))

csv

CSV delimiter.

A synonym for "," for use in preparing text for CSV files, or reading them.

>>> pykx.q.csv
pykx.CharAtom(q('","'))

fkeys

Foreign-key columns of a table.

>>> pykx.q('f:([x:1 2 3]y:10 20 30)')
pykx.Identity(q('::'))
>>> pykx.q('t: ([]a:`f$2 2 2; b: 0; c: `f$1 1 1)')
pykx.Identity(q('::'))
>>> pykx.q.fkeys('t')
pykx.Dictionary(q('
a| f
c| f
'))

insert

Insert or append records to a table.

>>> pykx.q('t: ([] a: `a`b`c; b: til 3)')
>>> pykx.q('t')
pykx.Table(q('
a b
---
a 0
b 1
c 2
'))
>>> pykx.q.insert('t', ['d', 3])
>>> pykx.q('t')
pykx.Table(q('
a b
---
a 0
b 1
c 2
d 3
'))

key

Where x is a dictionary (or the name of one), returns its keys.

>>> pykx.q.key({'a': 1, 'b': 2})
pykx.SymbolVector(q('`a`b'))

keys

Get the names of the key columns of a table.

>>> pykx.q['v'] = pykx.KeyedTable(data={'x': [4, 5, 6]}, index=[1, 2, 3])
>>> pykx.q('v')
pykx.KeyedTable(pykx.q('
idx| x
---| -
1  | 4
2  | 5
3  | 6
'))
>>> pykx.q.keys('v')
pykx.SymbolVector(q(',`idx'))

meta

Metadata for a table.

Column Information
c column name
t data type
f foreign key (enums)
a attribute
>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
...     'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
...     'sym': ['a', 'a', 'b', 'b'],
...     'p': pykx.LongVector([2, 4, 6, 8])
... })
>>> pykx.q.meta(df)
pykx.KeyedTable(q('
c   | t f a
----| -----
time| n
sym | s
p   | j
'))

ungroup

Where x is a table, in which some cells are lists, but for any row, all lists are of the same length, returns the normalized table, with one row for each item of a lists.

>>> a = pykx.Table([['a', [2, 3], 10], ['b', [5, 6, 7], 20], ['c', [11], 30]], columns=['s', 'x', 'q'])
>>> a
pykx.Table(pykx.q('
s x       q
------------
a (2;3)   10
b (5;6;7) 20
c ,11     30
'))
>>> pykx.q.ungroup(a)
pykx.Table(q('
s x  q
-------
a 2  10
a 3  10
b 5  20
b 6  20
b 7  20
c 11 30
'))

upsert

Add new records to a table.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b'], 'p': pykx.LongVector([2, 4, 6, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
-----
a   2
a   4
b   6
b   8
'))
>>> pykx.q.upsert(df, ['c', 10])
>>> pykx.Table(q('
sym p
------
a   2
a   4
b   6
b   8
c   10
'))

xasc

Sort a table in ascending order of specified columns.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xasc('p', df)
pykx.Table(q('
sym p
------
c   0
b   2
a   4
b   6
c   8
a   10
'))

xcol

Rename table columns.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xcol(pykx.SymbolVector(['Sym', 'Qty']), df)
pykx.Table(q('
Sym Qty
-------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xcol({'p': 'Qty'}, df)
pykx.Table(q('
sym Qty
-------
a   10
a   4
b   6
b   2
c   0
c   8
'))

xcols

Reorder table columns.

>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({
...     'time': np.array([1, 2, 3, 4], dtype='timedelta64[s]'),
...     'sym':['a', 'a', 'b', 'b'],
...     'p': pykx.LongVector([2, 4, 6, 8])
... })
>>> pykx.Table(df)
pykx.Table(q('
time                 sym p
--------------------------
0D00:00:01.000000000 a   2
0D00:00:02.000000000 a   4
0D00:00:03.000000000 b   6
0D00:00:04.000000000 b   8
'))
>>> pykx.q.xcols(pykx.SymbolVector(['p', 'sym', 'time']), df)
pykx.Table(q('
p sym time
--------------------------
2 a   0D00:00:01.000000000
4 a   0D00:00:02.000000000
6 b   0D00:00:03.000000000
8 b   0D00:00:04.000000000
'))

xdesc

Sorts a table in descending order of specified columns. The sort is by the first column specified, then by the second column within the first, and so on.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xdesc('p', df)
pykx.Table(q('
sym p
------
a   10
c   8
b   6
a   4
b   2
c   0
'))

xgroup

Groups a table by values in selected columns.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xgroup('sym', df)
pykx.KeyedTable(q('
sym| p
---| ----
a  | 10 4
b  | 6  2
c  | 0  8
'))

xkey

Set specified columns as primary keys of a table.

>>> import pandas as pd
>>> df = pd.DataFrame({'sym':['a', 'a', 'b', 'b', 'c', 'c'], 'p': pykx.LongVector([10, 4, 6, 2, 0, 8])})
>>> pykx.Table(df)
pykx.Table(q('
sym p
------
a   10
a   4
b   6
b   2
c   0
c   8
'))
>>> pykx.q.xkey('p', df)
pykx.KeyedTable(q('
p | sym
--| ---
10| a
4 | a
6 | b
2 | b
0 | c
8 | c
'))

Text

like

Whether text matches a pattern.

>>> pykx.q.like('quick', b'qu?ck')
pykx.BooleanAtom(q('1b'))
>>> pykx.q.like('brown', b'br[ao]wn')
pykx.BooleanAtom(q('1b'))
>>> pykx.q.like('quick', b'quickish')
pykx.BooleanAtom(q('0b'))

lower

Shift case to lower case.

>>> pykx.q.lower('HELLO')
pykx.SymbolAtom(q('`hello'))
>>> pykx.q.lower(b'HELLO')
pykx.CharVector(q('"hello"'))

ltrim

Remove leading nulls from a list.

>>> pykx.q.ltrim(b'    pykx    ')
pykx.CharVector(q('"pykx    "'))

md5

Message digest hash.

>>> pykx.q.md5(b'pykx')
pykx.ByteVector(q('0xfba0532951f022133f8e8b14b6ddfced'))

rtrim

Remove trailing nulls from a list.

>>> pykx.q.rtrim(b'    pykx    ')
pykx.CharVector(q('"    pykx"'))

ss

String search.

>>> pykx.q.ss(b'a cat and a dog', b'a')
pykx.LongVector(q('0 3 6 10'))

ssr

String search and replace.

>>> pykx.q.ssr(b'toronto ontario', b'ont', b'x')
pykx.CharVector(q('"torxo xario"'))

string

Cast to string.

>>> pykx.q.string(2)
pykx.CharVector(q(',"2"'))
>>> pykx.q.string([1, 2, 3, 4, 5])
pykx.List(q('
,"1"
,"2"
,"3"
,"4"
,"5"
'))

trim

Remove leading and trailing nulls from a list.

>>> pykx.q.trim(b'    pykx    ')
pykx.CharVector(q('"pykx"'))

upper

Shift case to upper case.

>>> pykx.q.upper('hello')
pykx.SymbolAtom(q('`HELLO'))
>>> pykx.q.upper(b'hello')
pykx.CharVector(q('"HELLO"'))

Operators

drop

Drop items from a list, entries from a dictionary or rows from a table.

Examples:

Drop the first 3 items from a list

>>> import pykx as kx
>>> kx.q.drop(3, kx.q('1 2 3 4 5 6'))
pykx.LongVector(pykx.q('4 5 6'))

Drop the last 10 rows from a table

>>> import pykx as kx
>>> tab = kx.Table(data={
...     'x': kx.q.til(100),
...     'y': kx.random.random(100, 10.0)
... })
>>> kx.q.drop(-10, tab)
pykx.Table(pykx.q('
x  y        
------------
0  3.927524 
1  5.170911 
2  5.159796 
3  4.066642 
4  1.780839
..
'))
>>> len(kx.q.drop(-10, tab))
90

coalesce

Merge two keyed tables ignoring null objects

Example:

Coalesce two keyed tables one containing nulls

>> tab1 = kx.Table(data={
...     'x': kx.q.til(10),
...     'y': kx.random.random(10, 10.0)
...     }).set_index('x')
>>> tab2 = kx.Table(data={
...     'x': kx.q.til(10),
...     'y':kx.random.random(10, [1.0, kx.FloatAtom.null, 10.0])
...     }).set_index('x')
>>> kx.q.coalesce(tab1, tab2)
pykx.KeyedTable(pykx.q('
x| y         z
-| ------------
0| 9.006991  10
1| 8.505909
2| 8.196014  10
3| 0.9982673 1
4| 8.187707
..
'))

fill

Replace nulls in lists, dictionaries or tables

Examples:

Replace null values in a list

>>> null_list = kx.random.random(10, [10, kx.LongAtom.null, 100])
>>> kx.q.fill(0, null_list)

Replace all null values in a table

>>> table = kx.Table(data={
...     'x': kx.random.random(10, [10.0, kx.FloatAtom.null, 100.0]),
...     'y': kx.random.random(10, [10.0, kx.FloatAtom.null, 100.0])
...     })
>>> kx.q.fill(10.0, table)

take

Select leading or trailing items from a list or dictionary, named entries from a dictionary, or named columns from a table

Examples:

Retrieve the last 3 items from a list

>>> lst = kx.q.til(100)
>>> kx.q.take(-3, lst)
pykx.LongVector(pykx.q('97 98 99'))

Retrieve named columns from a table using take

>>> table = kx.Table(data={
...     'x': kx.random.random(5, 10.0),
...     'y': kx.random.random(5, 10.0),
...     'z': kx.random.random(5, 10.0),
...     })
>>> kx.q.take(['x', 'y'], table)
pykx.Table(pykx.q('
x        y       
-----------------
6.916099 9.672398
2.296615 2.306385
6.919531 9.49975 
4.707883 4.39081 
6.346716 5.759051
'))

set_attribute

Set an attribute for a supplied list or dictionary, the supplied attribute must be one of: 's', 'u', 'p' or 'g'.

>>> kx.q.set_attribute('s', kx.q.til(10))
pykx.LongVector(pykx.q('`s#0 1 2 3 4 5 6 7 8 9'))
>>> kx.q.set_attribute('g', [2, 1, 2, 1])
pykx.LongVector(pykx.q('`g#2 1 2 1'))

join

Join atoms, lists, dictionaries or tables

>>> kx.q.join([1, 2, 3], [4, 5, 6])
pykx.LongVector(pykx.q('1 2 3 4 5 6'))

Join multiple dictionaries together

>>> kx.q.join({'x': 1, 'y': 2}, {'z': 3})
pykx.Dictionary(pykx.q('
x| 1
y| 2
z| 3
'))

Join multiple columns row wise

>>> t = kx.q('([]a:1 2 3;b:`a`b`c)')
>>> s = kx.q('([]a:10 11;b:`d`e)')
>>> kx.q.join(t, s)
pykx.Table(pykx.q('
a  b
----
1  a
2  b
3  c
10 d
11 e
'))

find

Find the first occurrence of an item(s) in a list

>>> lst = [10, -8, 3, 5, -1, 2, 3]
>>> kx.q.find(lst, -8)
pykx.LongAtom(pykx.q('1'))
>>> kx.q.find(lst, [10, 3])
pykx.LongVector(pykx.q('0 2'))

enum_extend

Extend a defined variable enumeration

>>> kx.q['foo'] = ['a', 'b']
>>> kx.q.enum_extend('foo', ['a', 'b', 'c', 'a', 'b'])
pykx.EnumVector(pykx.q('`foo$`a`b`c`a`b'))
>>> kx.q['foo']
pykx.SymbolVector(pykx.q('`a`b`c'))

Extend a filepath enumeration

>>> import os
>>> from pathlib import Path
>>> kx.q['bar'] = ['c', 'd']    # about to be overwritten
>>> kx.q.enum_extend(Path('bar'), ['a', 'b', 'c', 'b', 'b', 'a'])
pykx.EnumVector(pykx.q('`bar$`a`b`c`b`b`a'))
>>> os.system('ls -l bar')
-rw-r--r--  1 username  staff  14 20 Aug 09:34 bar
>>> kx.q['bar']
pykx.SymbolVector(pykx.q('`a`b`c'))

roll

Generate a random list of values with duplicates, for this the first parameter must be positive.

>>> kx.q.roll(3, 10.0)
pykx.FloatVector(pykx.q('3.927524 5.170911 5.159796'))
>>> kx.q.roll(4, [1, 'a', 10.0])
pykx.List(pykx.q('
`a
1
`a
10f
'))

deal

Generate a random list of values without duplicates, for this the first parameter must be negative.

>>> kx.q.deal(-5, 5)
pykx.LongVector(pykx.q('1 3 2 0 4'))
>>> kx.q.deal(-3, ['the', 'quick', 'brown', 'fox'])
pykx.SymbolVector(pykx.q('`the`brown`quick'))

dict

Generate a dictionary by passing two lists of equal lengths

>>> kx.q.dict(['a', 'b', 'c'], [1, 2, 3])
pykx.Dictionary(pykx.q('
a| 1
b| 2
c| 3
'))

enkey

Create a keyed table by passing an integer to a simple table. This is similar to set_index

>>> simple_tab = kx.Table(data = {
...     'x': [1, 2, 3],
...     'y': [4, 5, 6]
...     })
>>> kx.q.dict(1, simple_tab)
pykx.KeyedTable(pykx.q('
x| y
-| -
1| 4
2| 5
3| 6
'))

unkey

Remove the keys from a keyed table returning a simple table, this is similar to reset_index with no arguments

>>> keyed_tab = kx.Table(data = {
...     'x': [1, 2, 3],
...     'y': [4, 5, 6]
...     }).set_index(1)
>>> kx.q.unkey(0, keyed_tab)
pykx.Table(pykx.q('
x y
---
1 4
2 5
3 6
'))

enumeration

Enumerate a symbol list - First argument is a variable in q memory denoting a symbol list - Second argument is a vector of integers in the domain 0-length(first argument)

>>> kx.q['x'] = ['a', 'b', 'c', 'd']
>>> kx.q.enumeration('x', [1, 2, 3])
pykx.EnumVector(pykx.q('`x$`b`c`d'))

enumerate

Enumerate a list of symbols based on the symbols in a global q variable

>>> kx.q['d'] = ['a', 'b', 'c']
>>> y = ['a', 'b', 'c', 'b', 'a', 'b', 'c']
>>> kx.q.enumerate('d', y)
pykx.EnumVector(pykx.q('`d$`a`b`c`b`a`b`c'))

pad

Pad a supplied PyKX string (Python bytes) to the length supplied by the user. In the case that you are padding the front of a string use a negative value.

>>> kx.q.pad(-5, b'abc')
pykx.CharVector(pykx.q('"  abc"'))
>>> kx.q.pad(10, [b'test', b'string', b'length'])
pykx.List(pykx.q('
"test      "
"string    "
"length    "
'))

cast

Convert to another datatype, this should be a single lower case character byte, or name of the type. See https://code.kx.com/q/ref/cast/ for the accepted list.

>>> long_vec = kx.q('til 10')
>>> kx.q.cast('short', long_vec)
pykx.ShortVector(pykx.q('0 1 2 3 4 5 6 7 8 9h'))
>>> kx.q.cast(b'b', long_vec)
pykx.BooleanVector(pykx.q('0111111111b'))

tok

Interpret a PyKX string as a data value(s), this should use a single upper case character byte or a non-positive PyKX short value. See https://code.kx.com/q/ref/tok/ for more information on accepted lists for casting

>>> kx.q.tok(b'F', b'3.14')
pykx.FloatAtom(pykx.q('3.14'))
>>> float_int = kx.toq(-9, kx.ShortAtom)
>>> kx.qkx.toq(int(1), kx.ShortAtom)

compose

Compose a unary value function with another.

>>> f = kx.q('{2*x}')
>>> ff = kx.q('{[w;x;y;z]w+x+y+z}')
>>> d = kx.q.compose(f, ff)
>>> d(1, 2, 3, 4)
pykx.LongAtom(pykx.q('20'))