Short answer: It takes a function of N operands and creates a new function that applies the original to each set of corresponding elements from N same-length vectors.


We can categorize the ways in which q handles vectors into the following three groups:

1) Treat the vector as a single entity.

2) Perform an operation on each element of a vector.

3) Perform an operation on each set of corresponding elements from multiple vectors of the same length.

We use ‘ (each-both) to ask q to apply a function in the third manner.

Let’s review a few examples to distinguish the three forms of vector handling described above. Consider the , (join) operator, which takes two arguments and concatenates them. When used by itself, , (join) treats a vector as a single entity:

q)1 , 2
1 2
q)1 2 3 , 10
1 2 3 10
q)1 , 10 20 30
1 10 20 30
q)1 2 , 10 20 30
1 2 10 20 30
q)

Notice that the lengths of the two vectors to be joined doesn’t matter; in fact, they don’t have to be vectors.

Next, as an example of applying the same operation to each element of a vector, we can use \: (each-left) to append the letter “e” to each element in a vector of strings:

q)("car"; "far"; "mar") ,\: "e"
"care"
"fare"
"mare"
q)

Lastly, we’ll use ‘ (each-both) to join corresponding elements from two vectors of the same length (like zip from Python or Haskell):

q)1 2 3 ,' 10 20 30
1 10
2 20
3 30
q)

As an aside, the use of ‘ (each-both) is not needed for many built-in functions in q, because those functions (sometimes referred to as atomic functions in kx documentation) automatically assume that this is the desired behavior when presented with same-length vectors as arguments. The + operator is a good example:

q)1 2 3 + 10 20 30
11 22 33
q)

Even a user defined function, if that function’s body is exclusively made up of applications of atomic functions, does not require the use of ‘ (each-both) to display this behavior:

q)atomic: {[x; y] (x * x) + y * y}
q)atomic'[1 2 3; 10 20 30]
101 404 909
q)atomic[1 2 3; 10 20 30]  // ' not required
101 404 909
q){[x; y] atomic[x; y]}[1 2 3; 10 20 30]
101 404 909
q)

The last example shows that such user defined atomic functions are truly atomic in the eyes of q.

The following code simulates the behavior of ‘ (each-both) – on functions of two arguments – by creating a new function (that acts on vectors) from the function passed as an argument:

However, ‘ (each-both) doesn’t stop at two lists, which is why it is sometimes called multivalent each. Suppose we need to generate a bunch of html hyperlinks for a web page we are creating on-the-fly (perhaps in a custom http POST handler). Each link needs to have its own styling, so we want to add a distinct class attribute to each anchor tag.

The .h namespace includes numerous functions for generating HTML. The one we need is the .h.htac (html tag with attributes and closing tag) function:

 

q).h.htac[`a; `class`href ! ("myclass"; "kdbfaq.com"); "kdbfaq"]
"<a class=\"myclass\" href=\"kdbfaq.com\">kdbfaq</a>"
q)

Let’s wrap .h.htac (html tag with attributes and closing tag) up in a function to create a styled link:

 

We’ll store the information we need to generate the links in a table:

 

q)links
name        url                    class
----------------------------------------
"kx"        "http://kx.com"        "c1"
"Wikipedia" "http://wikipedia.com" "c2"
"kdbfaq"    "http://kdbfaq.com"    "c3"
q)

Now we can use ‘ (multivalent each) to generate all the links easily:

q)styled_link'[links `name; links `url; links `class]
"<a class=\"c1\" href=\"http://kx.com\">kx</a>"
"<a class=\"c2\" href=\"http://wikipedia.com\">Wikipedia</a>"
"<a class=\"c3\" href=\"http://kdbfaq.com\">kdbfaq</a>"
q)

Or, alternately, we can combine ‘ (multivalent each) with . (apply) for a shorter, more general approach to applying a function to each row in a table:

q)styled_link .' flip value flip links
"<a class=\"c1\" href=\"http://kx.com\">kx</a>"
"<a class=\"c2\" href=\"http://wikipedia.com\">Wikipedia</a>"
"<a class=\"c3\" href=\"http://kdbfaq.com\">kdbfaq</a>"
q)

On more wrinkle: sometimes ‘ (each) is used where \: (each-left) or /: (each-right) would be more explicit. For instance, our earlier example in which we appended the letter “e” to each element of a list of strings could have been written as follows:

q)("car"; "far"; "mar") ,' "e"
"care"
"fare"
"mare"
q)

We find the original, more explicit form, quicker and easier to read.

Short answer: When 1) projected or 2) modified by an adverb, e.g., :/: :\: or :’


Normally, the : (amend) function is used to assign a value to a name:

q)foo: 47
q)foo
47
q)

Like other built-in functions that take two arguments, : (amend) can be called using either infix notation (as above) or function call notation:

q):[foo; 747]
q)foo
747
q)

Note that : (amend) displays its special semantics (which it shares with assignments in all strict languages) of not evaluating its first argument when that argument is simply a name, regardless of whether : (amend) is invoked infix or functionally.

q)delete bar from `.    / make sure bar is not defined
q):[bar; 42]
q)bar
42
q)

On the other hand, : (amend) does evaluate its first argument when that argument is an expression, but : (amend) still produces l-values when it does so:

q)list: 0 1 2 3
q)list[0]: 47
q)list
47 1 2 3
q):[list 1 2 3; 10 20 30]
q)list
47 10 20 30
q)

Based on the previous examples, you might be tempted create a projection from : (amend) and a left-hand side, but it turns out you can’t:

q):[foo]
'foo
q)

It is possible to close the first argument to : (amend), but the resulting projection is no longer an assignment; it is an identity function:

q)foo: 42
q)(:[foo])[47]
47
q)foo
42
q)

In fact, the value attached to the first argument of : (amend) is irrelevant:

q)(:[`xyzzy])[47]
47
q)

Closing the second argument will cause : (amend) to return the same value always:

q)f: :[; 3]     / bind the 2nd argument
q)f 18          / no matter what we pass
3
q)f "hello"     / f will always return 3
3
q)

The other case when : (amend) does not perform assignment is when it is modified by an adverb:

q)list1: 0 1 2 3
q)list2: 4 5 6 7
q)(list1; list2) :\: 10 20 30 40   / we get the rhs
10 20 30 40                        / once for each list
10 20 30 40
q)list1                            / neither list
0 1 2 3
q)list2                            / has been modified
4 5 6 7
q)list2 :/: 0 1 2 3
0 1 2 3
q)list1[0 1 2 3] :' 10 20 30 40
10 20 30 40
q)

Short answer:

count list
or
count each column_name
to get the length of a list-valued field in a query.


The length of any list can be found using the count function; the only complication occurs with certain applications of count in queries. We’ll illustrate with a table of simulated trade data:

q)trade
time         sym price size
---------------------------
09:30:17.623 glo 26.79 3200
09:30:26.602 ojb 28.17 1600
09:30:33.657 fjc 91.31 5400
09:30:40.884 knb 59.7  2900
09:31:19.256 apl 1.26  7900
..
q)

The following query uses count to return the number of rows that satisfy the where clause:

q)exec count i from trade where sym = `aif
6
q)

This is usually what you want.

However, suppose we created another table (perhaps to improve the performance of certain queries) that grouped prices for each symbol:

q)grouped: select price by sym from trade
q)grouped
sym| price                                                   ..
---| --------------------------------------------------------..
acl| 18.1 85.5 86.31 45.65 10.91 31.25 5.49 51.66 1.02 31.82 ..
aif| 44.02 47.74 11.83 14.28 85.11 99.09                     ..
alk| 51.12 16.7 78.71 96.56 26.55 32.09 33.66 30.01 83.24 30...
amg| 59.25 56.18 92.63 46.57 57.25 14.58 69.21 88.25 94.1 28...
aog| 92.59 51.52 96.95 83.2 6.21 59.77 44.19 94.19 3.13 41.94..
..
q)

In table grouped, the price column is of type list-of-float – note the uppercase type letter F:

q)meta grouped
c    | t f a
-----| -----
sym  | s
price| F

It appears that we can retrieve the prices for a given symbol easily enough:

q)exec price from grouped where sym = `aif
44.02 47.74 11.83 14.28 85.11 99.09
q)

Suppose, however, that we want to know how many trades occurred for a particular symbol:

q)exec count price from grouped where sym = `aif
1
q)

What went wrong? A where function yields a list of row indexes that meet the constraints, and then each projection (i.e., the column names between exec and from — in this case, price) yields a list of corresponding field values. Since the number of rows that met our sole constraint is 1, the result of the projection is an untyped list with a single element:

q)type exec price from grouped where sym = `aif
0h
q)count exec price from grouped where sym = `aif
1
q)

Projection results are the arguments to aggregation functions in queries. In other words, the untyped list in our example is the same as the one passed to count. Since the projection’s single element contains the list of prices we want to count, the way out is to combine count with first:

q)exec count first price from grouped where sum = `aif
6
q)

Applying the same logic when counting the trades for every symbol, we need to use count each:

q)select count price by sym from grouped
sym| price
---| -----
acl| 1
aif| 1
alk| 1
amg| 1
aog| 1
..
q)select count each price by sym from grouped
sym| price
---| -----
acl| 14
aif| 6
alk| 10
amg| 12
aog| 13
..
q)

Constraints in where clauses behave the same as well. Consider the following select statement:

q)t
x y z
-------------
a 1 "xyzzy"
b 2 "grue"
c 3 "frobozz"
q)select from t where 5 < count z
x y z
-----
q)

Newcomers to q often expect the above query to return the rows from t whose z column has more than 5 characters (i.e., c 3 frobozz). Rather than counting the contents of each z field, however, count is actually counting the list t `z:

q)count t `z
3
q)t `z
"xyzzy"
"foobar"
"frobozz"
q)

This insight suggests the solution:

q)count each t `z
5 6 7
q)select from t where 5 < count each z
x y z
-------------
c 3 "frobozz"
q)