Janet 1.1.0-dev Documentation

Data Structures

Once you have a handle on functions and the primitive value types, you may be wondering how to work with collections of things. Janet has a small number of core data structure types that are very versatile. Tables, Structs, Arrays, Tuples, Strings, and Buffers, are the 6 main built in data structure types. These data structures can be arranged in a useful table describing their relationship to each other.

Interface Mutable Immutable
Indexed Array Tuple
Dictionary Table Struct
Bytes Buffer String (Symbol, Keyword)

Indexed types are linear lists of elements than can be accessed in constant time with an integer index. Indexed types are backed by a single chunk of memory for fast access, and are indexed from 0 as in C. Dictionary types associate keys with values. The difference between dictionaries and indexed types is that dictionaries are not limited to integer keys. They are backed by a hashtable and also offer constant time lookup (and insertion for the mutable case). Finally, the 'bytes' abstraction is any type that contains a sequence of bytes. A 'bytes' value or byteseq associates integer keys (the indices) with integer values between 0 and 255 (the byte values). In this way, they behave much like Arrays and Tuples. However, one cannot put non integer values into a byteseq.

The table below summarizes the big-O complexity of various operations and other information on the built-in data structures. All primitive operations on data structures will run in constant time regarding the number of items in the data structure.

Data Structure Access Insert/Append Delete Space Complexity Mutable
Array * O(1) O(1) O(1) O(n) Yes
Tuple O(1) - - O(n) No
Table O(1) O(1) O(1) O(n) Yes
Struct O(1) - - O(n) No
Buffer O(1) O(1) O(1) O(n) Yes
String/Keyword/Symbol - - - O(n) No

*: Append and delete for an array correspond to array/push and array/pop. Removing or inserting elements at random indices will run in O(n) time where n is the number of elements in the array.

(def mytuple (tuple 1 2 3))

(def myarray @(1 2 3))
(def myarray (array 1 2 3))

(def mystruct {
 :key "value"
 :key2 "another"
 1 2
 4 3})

(def another-struct
 (struct :a 1 :b 2))

(def my-table @{
 :a :b
 :c :d
 :A :qwerty})
(def another-table
 (table 1 2 3 4))

(def my-buffer @"thisismutable")
(def my-buffer2 @``This is also mutable``)

To read the values in a data structure, use the get function. The first parameter is the data structure itself, and the second parameter is the key.

(get @{:a 1} :a) # -> 1
(get {:a 1} :a) # -> 1
(get @[:a :b :c] 2) # -> :c
(get (tuple "a" "b" "c") 1) # -> "b"
(get @"hello, world" 1) # -> 101
(get "hello, world" 0) # -> 104