q vs python: Lists

(Series) A side-by-side comparison of q/kdb+ and python for qbies (q newbies).

This cheat sheet is a list of code snippets that do the same thing in q and python -- something I wished existed when I first came to q/KDB+ from python. Note that in both languages, the code shown is sometimes not the most elegant or succinct; that's on purpose because I wanted to show the same constructs in both languages. For a comprehensive intro to q, check out Q for Mortals.

Note q code snippets are edited to have line breaks for readability (my opinion; ymmv). Multiline statements do not work at the prompt, but they do work in scripts. See docs.

Versions: q (3.6), python (3.7)

Init*

q)x:1 2 3
q)x
1 2 3

q)til 5
0 1 2 3 4
>>> x = [1, 2, 3]
>>> x
[1, 2, 3]

>>> list(range(5))
[0, 1, 2, 3, 4]

Apply function to items in a list*

q)5 + 10 * til 3
0 15 25

q)zeroIfEven:{?[0=x mod 2;0;x]}


q)zeroIfEven til 10
0 1 0 3 0 5 0 7 0 9
>>> [5 + 10 * i for i in range(3)]
[5, 15, 25]

>>> def zero_if_even(x):
...     return 0 if x % 2 == 0 else x

>>> [zero_if_even(i) for i in range(10)]
[0, 1, 0, 3, 0, 5, 0, 7, 0, 9]

Slice*

q)x:`zero`one`two
q)x 2 0
`two`zero

q)reverse x
`two`one`zero
>>> x = ['zero', 'one', 'two']
>>> [x[i] for i in [2, 0]]
['two', 'zero']

>>> x[::-1]
['two', 'one', 'zero']

Filter*

q)xs:`zero`one`two`san
q)bs:1101b
q)xs where bs
`zero`one`san

/ Keep evens
q)x where 0 = (x:til 10) mod 2
0 2 4 6 8
>>> xs = ['zero', 'one', 'two', 'san']
>>> bs = [True, True, False, True]
>>> [x for x, b in zip(xs, bs) if b]
['zero', 'one', 'san']

# Keep evens
>>> [_ for _ in range(10) if _ % 2 == 0]
[0, 2, 4, 6, 8]

Note that where returns the indexes where its argument is true. In other words, where 0110b returns 1 2.

Replace items*

q)list:10 11 12 13
q)ixsToReplace:1 3
q)replaceWith:777
q)@[list; ixsToReplace; :; replaceWith]
10 777 12 777
>>> lst = [10, 11, 12, 13]
>>> ixs_to_replace = [1, 3]
>>> replace_with = 777
>>> [replace_with if i in ixs_to_replace else v for i, v in enumerate(lst)]
[10, 777, 12, 777]

Apply function based on condition*

On the q side, we're doing the ternary form of "Amend At": @[d; i; u]

q)list:10 11 12 13
q)isEven:{0=x mod 2}
q)replaceWith:777
q)@[list; where isEven list; neg]
-10 11 -12 13
>>> lst = [10, 11, 12, 13]
>>> is_even = lambda x: x % 2 == 0
>>> neg = lambda x: -x
>>> [neg(x) if is_even(x) else x for x in lst]
[-10, 11, -12, 13]

Count occurence of unique items in list*

q)xs:11 12 12 13 13 13

q)distinct xs
11 12 13

q)count each group xs
11| 1
12| 2
13| 3
>>> xs = [11, 12, 12, 13, 13, 13]

>>> set(xs)
set([11, 12, 13])

>>> from collections import Counter
>>> Counter(xs)
Counter({13: 3, 12: 2, 11: 1})