Data structures
There are three data structures in q: atom, list and dictionary.
- Atom
-
The simplest structure is no structure. An atom is indivisible, has no items and cannot be indexed.
- List
-
An embraced sequence of zero or more items, separated by semicolons.
-
A list is ordered: its items are indexed by the natural numbers.
- List item
-
A list item can be an atom, a list, or a dictionary.
- General list
-
List notation: a general list is a series of items separated by semicolons and embraced by parens.
("a";`foggy;1942.04.02;in)
- Parse tree
-
A list in which the first item is a function, and the rest its arguments.
(*;6;7)
- Argument and expression lists
-
are embraced by square brackets.
["a";`foggy;1942.04.02;in] / argument list [a<b;c:2*a*b;foo::c%42] / expression list
See Lambda Notation and Applying Functions for their use.
- Vector
-
A list in which all items are data atoms of the same type.
-
The type of a vector is the negation of the type of one of its items.
- Vector notation
-
Vector literals have their own notation according to datatype.
1 2 3 4 / long 1 2.0 3 4 / float "abcdef" / char `abc`def`xyz / symbol 2023.09 2023.10m / month ..
- Dictionary
-
A pair of same-length lists: the key and the value.
`alice`bob`carol`ted!25 37 32 35
The key list items are the indices of the dictionary.
- Like dictionaries
-
Like dictionaries have identical key lists. (The order of keys matters.)
- Simple table
-
A simple table is both
- a list of like dictionaries
- a list of named same-length lists
e.g.
q)name:`alice`bob`carol q)age:25 37 32 q)hair:`fair`black`blonde q)k:`name`age`hair q)show t1:([]name;age;hair) name age hair ---------------- alice 25 fair bob 37 black carol 32 blonde q)t2:k!/:((`alice;25;`fair);(`bob;37;`black);(`carol;32;`blonde)) q)t3:([]name:`alice`bob`carol;age:25 37 32;hair:`fair`black`blonde) q)t1~/:(t2;t3) 11b
- Keyed table
-
A dictionary in which both key and value are tables.
q)id:11 12 13 q)([name;id] hair;age) name id| hair age --------| ---------- alice 11| fair 25 bob 12| black 37 carol 13| blonde 32
- Conformability
-
Two or more data structures conform if
- they are lists of the same length, in which corresponding items conform, or
- one or both is an atom.
Many primitives iterate implicitly through items of conformable lists.
1 2 3 + 4 5 6
- Scalar extension
-
The matching of an atom with every item in a list.
1 2 3 + 4
Scalar extension applies to atoms but not to 1-item lists.
q)1 2 3 + 4 5 6 7 q)1 2 3 + 1#4 'length [0] 1 2 3 + 1#4 ^
More on this later in Implicit Iteration.
Enlist
List notation is syntactic sugar for the enlist
keyword.
q)(1;now;`abc;"abc") ~ enlist[1;now;`abc;"abc"]
1b
This means enlist
is variadic: it can take any number of arguments.
In particular, it can take more than 8.
A list with items omitted is a projection of enlist
.
q)("Mary";"Khiloni";"Xin")(;"likes";)'("Ajay";"Carol";"Ingrid")
"Mary" "likes" "Ajay"
"Khiloni" "likes" "Carol"
"Xin" "likes" "Ingrid"
One-item lists
List notation provides no way to describe a list with one item.
q)type(3) / atom
-7h
The display form of a one-item list prefixes a comma.
q)1#3
,3
This is not a literal notation.
q),3
',
[0] ,3
^
The Join operator is binary, so cannot be used with prefix syntax.
You can make a one-item vector with the Take operator.
q)type 1#3
7h
You can make a one-item vector by joining an atom to the general empty list.
q)type (),`ibm
11h
The enlist
keyword makes any argument the sole item of a list.
q)count enlist 1 2 3
1
Type promotion
Assigning an atom to an item of a vector of another type signals a type error.
q)a:til 4
q)a[1]:0b
'type
[0] a[1]:0b
^
q)@[til 4;1;:;1.]
'type
[0] @[til 4;1;:;1.]
^
A general list is silently promoted to a vector at the first opportunity.
q)type a:(1;2;3.14159;4) / general list
0h
q)@[a;2;:;3] / vector
1 2 3 4
q)type @[a;2;:;3]
7h
Dictionaries
Key lists are often symbol vectors, but the structure is perfectly general: a dictionary can be made of any two lists of the same length, using the Dict !
operator.
q)show d:`ATW`KEI`SJT!("Whitney";"Iverson";"Taylor")
ATW| "Whitney"
KEI| "Iverson"
SJT| "Taylor"
q)type d / a dictionary has type 99
99h
The interpreter does not check for duplicate keys.
Ensure you have no duplicate key items. A dictionary with duplicate key items will behave in ways you would struggle to predict.
Are lists dictionaries?
Arguably, a list is a dictionary in which the key is til count
of the items.
Conversely, a dictionary is a more general form of list, in which you control the index.
This has implications for indexing.
- The indices of a list
L
aretil count L
. - The indices of a dictionary
k!v
arek
.
The syntax of indexing is the same for lists and dictionaries.
q)svect:`zero`one`two`three`four`five / symbol vector
q)sdict:0 1 2 3 4 5!`zero`one`two`three`four`five / symbol dictionary
q)svect 4 2
`four`two
q)sdict 4 2
`four`two
Tables
A table is a list of named same-length lists.
q)species:`cow`duck`python`snail
q)genus:`mammal`bird`reptile`mollusc
q)feet:4 2 0 1
q)show a:([]species;genus;feet)
species genus feet
--------------------
cow mammal 4
duck bird 2
python reptile 0
snail mollusc 1
A table is also a list of like dictionaries.
q)c:`species`genus`feet!(`cow;`mammal;4)
q)d:`species`genus`feet!(`duck;`bird;2)
q)p:`species`genus`feet!(`python;`reptile;0)
q)s:`species`genus`feet!(`snail;`mollusc;1)
q)show b:(c;d;p;s)
species genus feet
--------------------
cow mammal 4
duck bird 2
python reptile 0
snail mollusc 1
These two views of a table are equally valid.
q)a~b / does a match b?
1b
q)type a
98h
Notation
Tables are first-class objects in q. They have their own notation.
A table is written as one or more conformable columns, separated by semicolons and prefixed by a list of zero or more key columns embraced by square brackets, all embraced by parentheses.
Columns
A column is either:
- the name of a variable, which provides both column name and value
- a value assigned to a name, which becomes the column name
- a value, in which case the column name is provided by q
Examples:
q)species:`cow`duck`python`snail
q)genus:`mammal`bird`reptile`mollusc
q)feet:4 2 0 1
q)([]species;genus;feet)
species genus feet
--------------------
cow mammal 4
duck bird 2
python reptile 0
snail mollusc 1
q)([`a`b`c`d]`mammal`bird`reptile`mollusc;feet:4 2 0 1;99)
x| x feet x1
-| ---------------
a| mammal 4 99
b| bird 2 99
c| reptile 0 99
d| mollusc 1 99
Exercises
No peeking.
Attempt each exercise before looking at its answer.
The exercises clarify your thinking. Reading answers does not.
-
Write an example of a vector literal of each data type. Which data types do not have a notation for vector literals?
Answer
See the Datatypes. You should have examples for these types:
1011b / boolean 0x123456 / byte 0 1 2h / short 0 1 2i / int 0 1 2 / long 0 1 2e / real 0 1 2f / float "012" / char `12`3 / symbol 2023.10.27D14:10:36.529000000 2023.10.27D14:10:42.613000000 / timestamp 2023.01 2023.02 2023.03 / month 2023.01.01 2023.01.02 2023.01.03 / date 2023.10.27T14:10:36.529 2023.10.27T14:10:36.529 / datetime 0D00:00:00.000000001 0D00:00:00.000000002 / timespan 14:01 14:02 14:03 / minutes 14:01:01 14:01:02 14:01:03 / seconds 14:01:01.001 14:01:01.002 14:01:01.003 / time
There is no literal notation for GUID vectors.
-
If you use list notation rather than writing a vector literal, is the result a vector or a general list?
Answer
q)type (1;2;3;4) / vector 7h q)1 2 3 4 ~ (1;2;3;4) 1b
-
Write a list of functions. What is its datatype?
Answer
q)type each(count;+;ssr;<>\;{x*x}) 101 102 100 108 100h q)type(count;+;ssr;<>\;{x*x}) 0h
A general list. But what if the functions are all of the same type?
q)type each(+;-;%) 102 102 102h q)type(+;-;%) 0h
No: a list of functions is a general list.
-
Write a lambda that returns a list argument unchanged, but an atom as a 1-item list.
Answer
Some possible answers:
The last lambda above could simply be replaced by the projection{0<type x;(),x;x} {0<type x;1#x;x} {(1&neg type x)enlist/x} {(),x}
(),
. -
Can you demote a vector to a general list by joining it to an empty general list?
Answer
No, you cannot demote a vector by joining it to an empty general list.
q)type 1 2 3,() 7h q)type (),1 2 3 7h q)1 2 3 ~ (),1 2 3 1b
-
Your application keeps state (user queries) in a general list. The query parameters may be of different types, but if they happened to be the same, the list could get silently promoted to a vector and unable to record queries of any other type. How can you ensure the list is never promoted to a vector?
Answer
You can protect a general list from unintended promotion by including a function. A list with a function as an item will always be a general list.
Any item will do, but using the first item means the list can easily vary in length.
Any function will do, but using the Identity function
::
prevents the list being taken for a parse tree.Of course, as a list item, the Identity function is the general null.query:(::;`first;"second";reciprocal 3)
-
A sparse array has many indices but few values. Write a sparse integer array
sa
with a million indices but non-zero values100 200 300
(only) at indices748428 5480 474634
.What is the result of
sa[748428 5490 474634 1000001
]? What is the highest index ofsa
?Answer
Nothing prevents us defining the sparse array as a simple list.
q)sal: @[1000000#0N;748428 5480 474634;:;] 100 200 300 / simple list q)sal 748428 5490 474634 1000001 100 0N 300 0N
But what a waste of space. Index 5490 returns the null assigned there, and index 1000001 returns a null as the index is invalid.
q)sa:748428 5480 474634!100 200 300 q)sa 748428 5490 474634 1000001 100 0N 300 0N
Above, indices 5490 and 1000001 are both invalid and return nulls.
The highest actual index of
sa
is 748428, but its highest possible index is long infinity.q)max key sa 748428 q)sa 0W 0N
Both
sal
andsa
can be read at any integer index.q)sa[900000000] 0N q)sal[900000000] 0N
But only
sa
can have values set at indices above 1000000.q)sa[900000000]:99 q)sal[900000000]:99 'length [0] sal[100000000]:99 ^
-
Write a ternary lambda
at
that indexesx
aty
, but for invalid indices returnsz
instead of nulls.Answer
The Fill operator
^
replaces null items.q)0^sa 748428 5490 474634 1000001 100 0 300 0 q){z^x y}[sa;748428 5490 474634 1000001;99] 100 99 300 99
-
Does a dictionary have an order? If so, can it be sorted?
Answer
A dictionary is a pair of lists. Lists are ordered, so a dictionary is sortable.
q)sa 748428| 100 5480 | 200 474634| 300 q)desc sa / sort by value 474634| 300 5480 | 200 748428| 100 q){k!x k:desc key x}sa / sort by key 748428| 100 474634| 300 5480 | 200
-
Make a list of dictionaries which have the same key items but not all in the same order. What type does it have? Write a lambda that takes a list of dictionaries whose keys have the same items and returns them as a table.
Answer
q)/similar - but not like - dictionaries. q)show sbnld:(`a`b`c!10 20 30;`c`b`a!40 50 60) `a`b`c!10 20 30 `c`b`a!40 50 60 q){x@\:key first x} sbnld 10 20 30 60 50 40
-
Define the table written above as
([]species;genus;feet)
. How many other ways can you find to construct this table? Show that each result matches the first.Answer
species:`cow`duck`python`snail genus:`mammal`bird`reptile`mollusc feet:4 2 0 1 ([]species;genus;feet) ([]species:`cow`duck`python`snail; genus:`mammal`bird`reptile`mollusc;feet:4 2 0 1) k:`species`genus`feet k!/:flip(`cow`duck`python`snail;`mammal`bird`reptile`mollusc;4 2 0 1) k!/:((`cow;`mammal;4);(`duck;`bird;2);(`python;`reptile;0);(`snail;`mollusc;1))
-
Make a table in which one column is specified as an atom. How is the column filled?
Answer
q)([]species;genus;feet;extinct:0b) species genus feet extinct ---------------------------- cow mammal 4 0 duck bird 2 0 python reptile 0 0 snail mollusc 1 0
Scalar extension applies: the atom fills every item in the column.