Dictionaries and Tables | DefconQ
Skip to main content
Stay up to date with the latest blogs posts - subscribe to my free Substack newsletter now Free Substack Newsletter or follow me on Medium
On this page<br>Dictionaries and Tables
In this blog post, we explore two key data types native to KDB/Q: Dictionaries and Tables . Unlike mainstream programming languages like Java, which lack native support for these data types and require alternative structures (e.g., Java HashMap for dictionaries or Java ArrayList for lists of rows to represent tables), KDB/Q inherently supports both Dictionaries and Tables. Understanding these data structures is crucial for leveraging the speed and performance of KDB/Q to build efficient big data applications. In the following sections, we will examine the most important concepts of both data types, a in detail explanation of dictionaries and tables is beyond the scope of this blog post and can be found in Chapter 5 - Dictionaries and Chapter 8 - Tables of Q for Mortals.
note<br>As noted on the reference page at code.kx.com, dictionaries are of type 99h, while tables are of type 98h.
Dictionaries
In its simplest form, a dictionary is simply a mapping of a list of keys to a list of values, and it can be created using the bang operator !. Let's look at an example:
Creating Dictionaries
// Create a list of keys<br>q)k:`a`b`c<br>// Create a list of values<br>q)v:1 2 3<br>// Create the mapping between keys and values<br>q)k!v<br>a| 1<br>b| 2<br>c| 3<br>// Create a dictionary directly<br>q)`a`b`c!1 2 3<br>a| 1<br>b| 2<br>c| 3
tip<br>The keywords key and value can be used to extract the keys and values from a dictionary, respectively.<br>q)d:`a`b`c!1 2 3<br>q)key d<br>`a`b`c<br>q)value d<br>1 2 3
Dictionaries are highly flexible data structures. The main constraint when creating a dictionary is that the length of the keys list must match the length of the values list. If they don't match, a length error will occur.
q)`a`b`c!1 2 3 4<br>'length<br>[0] `a`b`c!1 2 3 4
To demonstrate the flexibility of dictionaries, note that the type of the list of keys or values doesn’t have to be homogeneous. However, once you create a homogeneous list of keys or values, any new key or value added must match the existing types. This might sound complex, but it's easier to understand with some examples. Let's take a look.
// Create a dictionary with a list of non-homogenous keys<br>q)show d:(`a;10;"C")!1 2 3<br>`a | 1<br>10 | 2<br>"C"| 3<br>// Add a new key of type integer<br>q)d[2]:4<br>q)d<br>`a | 1<br>10 | 2<br>"C"| 3<br>2 | 4<br>// Add another key of type symbol<br>q)d[`b]:9<br>q)d<br>`a | 1<br>10 | 2<br>"C"| 3<br>2 | 4<br>`b | 9
As shown in the example above, the keys of our dictionary can be of different types, allowing us to add new keys of any type. However, the values of the dictionary are all long 7h. Attempting to add a record where the value type doesn't match the current value types will result in a type error.
// Verify the data type of the keys of our dictionary<br>q)type value d<br>7h<br>// Trying to add a new record with a symbol as value<br>q)d["z"]:`hello<br>'type<br>[0] d["z"]:`hello
With the release of KDB/Q version 4.1, KX introduced a new dictionary syntax that enhances both the readability and flexibility of the language. In KDB/Q 4.1, you can now define dictionaries as follows:
q)([a:1;b:2;c:3])<br>a| 1<br>b| 2<br>c| 3
This is especially useful for creating empty or singleton dictionaries, which was quite verbose and cumbersome before version 4.1. See for yourself:
// Creating an empty, untyped dictionary<br>q)d:()!()<br>q)0N!d<br>()!()<br>// Creating an empty dictionary with keys of type integer and values of type symbol<br>q)d:(`int$())!`symbol$()<br>q)0N!d<br>(`int$())!`symbol$()<br>// Creating a singleton dictionary<br>q)enlist[`a]!enlist 3<br>a| 3
In contrast, with KDB/Q version 4.1 above dictionary definitions became much easier and more readable
// Creating an empty dictionary<br>q)d:([])<br>q)0N!d<br>(`symbol$())!()<br>// Creating a singleton dictionary<br>q)d:([a:3])<br>q)d<br>a| 3
Indexing into a dictionary
When you index into a dictionary, you are essentially performing a dictionary lookup, accessing a dictionary d to retrieve the value v at the specified key k. You can index into a dictionary using both, brackets and postfix notation
q)d:`a`b`c!1 2 3<br>// Indexing into a dictionary using bracket notation<br>q)d[`a]<br>// Indexing into a dictionary using postfix notation<br>q)d`a<br>// Ensuring both notations return the same result<br>q)d[`a]~d`a
You can also retrieve multiple elements using a list of keys as index
q)d:`a`b`c!1 2 3<br>q)d[`a`b]<br>1 2<br>q)d`a`b<br>1 2
However, due to the flexibility of dictionaries, their keys don't have to be unique, allowing the same key to be used multiple times. This can lead to unexpected results when retrieving elements stored at a key that's used more than once.
q)d:`a`b`c`a`b`c`d!til 7<br>q)d<br>a| 0<br>b| 1<br>c| 2<br>a| 3<br>b| 4<br>c| 5<br>d| 6<br>q)d`a<br>q)d`b<br>q)d?3<br>`a
Reverse Lookup: Finding values
Indexing into a dictionary is straightforward and a common operation. However, there are times when we need to perform the reverse operation:...