#### Janet 1.3.1 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
```

To update a mutable data structure, use the `put`

function. It takes 3 arguments, the data structure,
the key, and the value, and returns the data structure. The allowed types keys and values
depend on what data structure is passed in.

```
(put @[] 100 :a)
(put @{} :key "value")
(put @"" 100 92)
```

Note that for Arrays and Buffers, putting an index that is outside the length of the data structure will extend the data structure and fill it with nils in the case of the Array, or 0s in the case of the Buffer.

The last generic function for all data structures is the `length`

function. This returns the number of
values in a data structure (the number of keys in a dictionary type).