elm-scotland / elm-tries / Trie

A trie mapping unique strings to values.

Data structure


type Trie comparable a

A trie mapping keys to values, where the keys are List comparable.

A Trie is a lot like a Dict except the keys are expanded into lists. Keys that have common lists as prefixes share space, and it is possible to efficiently search for keys matching a particular prefix.

Build

empty : Trie comparable a

Create an empty trie.

singleton : List comparable -> a -> Trie comparable a

Create a trie with one key-value pair.

insert : List comparable -> a -> Trie comparable a -> Trie comparable a

Insert a key-value pair into a trie. Replaces value when there is a collision.

update : List comparable -> (Maybe a -> Maybe a) -> Trie comparable a -> Trie comparable a

Update the value of a trie for a specific key with a given function.

remove : List comparable -> Trie comparable a -> Trie comparable a

Remove a key-value pair from a trie. If the key is not found, no changes are made.

Query

isEmpty : Trie comparable a -> Basics.Bool

Determine if a trie is empty.

`isEmpty empty == True`

member : List comparable -> Trie comparable a -> Basics.Bool

TODO: I think this will match key prefixes? Probably should not for the Dict API.

get : List comparable -> Trie comparable a -> Maybe a

Get the value associated with a key. If the key is not found, return Nothing.

size : Trie comparable a -> Basics.Int

Determine the number of key-value pairs in the trie.

Lists

keys : Trie comparable a -> List (List comparable)

Get all of the keys in a trie, sorted from lowest to highest.

values : Trie comparable a -> List a

Get all of the values in a trie, in the order of their keys.

toList : Trie comparable a -> List ( List comparable, a )

Convert a trie into an association list of key-value pairs, sorted by keys.

fromList : List ( List comparable, a ) -> Trie comparable a

Convert an association list into a trie.

Transform

map : (List comparable -> a -> b) -> Trie comparable a -> Trie comparable b

Apply a function to all values in a trie.

foldl : (List comparable -> a -> b -> b) -> b -> Trie comparable a -> b

Fold over the key-value pairs in a trie from lowest key to highest key.

foldr : (List comparable -> a -> b -> b) -> b -> Trie comparable a -> b

Fold over the key-value pairs in a trie from highest key to lowest key.

Due to the way shorter keys are nearer the top of the trie this fold function has to hold more pending nodes in memory in order to fold in order from the highest key to the lowest key. For this reason it is less efficient than foldl and foldl should be preferred unless the ordering is important.

filter : (List comparable -> a -> Basics.Bool) -> Trie comparable a -> Trie comparable a

Keep only the key-value pairs that pass the given test.

partition : (List comparable -> a -> Basics.Bool) -> Trie comparable a -> ( Trie comparable a, Trie comparable a )

Partition a trie according to some test. The first trie contains all key-value pairs which passed the test, and the second contains the pairs that did not.

Combine

union : Trie comparable a -> Trie comparable a -> Trie comparable a

Combine two tries. If there is a collision, preference is given to the first trie.

intersect : Trie comparable a -> Trie comparable a -> Trie comparable a

Keep a key-value pair when its key appears in the second trie. Preference is given to values in the first dictionary.

diff : Trie comparable a -> Trie comparable b -> Trie comparable a

Keep a key-value pair when its key does not appear in the second trie.

merge : (List comparable -> a -> result -> result) -> (List comparable -> a -> b -> result -> result) -> (List comparable -> b -> result -> result) -> Trie comparable a -> Trie comparable b -> result -> result

The most general way of combining two tries. You provide three accumulators for when a given key appears:

  1. Only in the left trie.
  2. In both tries.
  3. Only in the right trie.

You then traverse all the keys from lowest to highest, building up whatever you want.

Trie specific search operations.


type Match comparable

Match describes how a flexible search over a trie will proceed.

The Break, ContinueIf and ContinueIfOneOf options allow a trie to be traversed efficiently without exploring unnecessary keys.

The Wildcard and ContinueIfOneOf options allow flexible matching within a trie. Functions such as case-insensitive matching, fuzzy matching or regular expression matching can be implemented using these options.

break : Match comparable

A match step that breaks on the current node.

wildcard : Match comparable

A match step follows all nodes after the current node.

continueIf : comparable -> Match comparable

A match step that follows only one node that exactly matches the next comparable in the key.

continueIfOneOf : List comparable -> Match comparable

A match step that follows one or more nodes that exactly match the specified next comparables in the key.

match : (Maybe comparable -> Maybe a -> context -> b -> ( b, context, Match comparable )) -> b -> context -> Trie comparable a -> b

Performs a flexible matching fold over a trie from the lowest to the highest key in order.

Suppose the function passed in has this form:

searchFn maybeKeyPart maybeValue context accum = ...

The maybeKeyPart parameter will be set to the next item from the key being scanned as a list. This is a Maybe as the empty list can be a key in a trie. In practice the value Nothing will only be passed to this function on the first call when the empty key is present.

The maybeValue parameter will be set to any value found at the current position in the trie.

The context parameter will be held against the particular node in the trie being explored. When and if that node is returned to in order to explore other key paths in the trie, the context for that node will be restored. The trie is explored using a depth first search, and the contexts are held in a stack of pending nodes to explore. An example use of the context might be to hold the remaining portion of a key to be matched.

The accum parameter is used like the accumulator in a fold, it can be updated on each node explored.

The context parameter is restored when back-tracking to explore other possible keys, but the accum parameter is carried accross the whole search. In that sense context is like a local variable and accum is like a global variable.

expand : List comparable -> Trie comparable a -> List ( List comparable, a )

Given a prefix, finds all keys that begin with that prefix.

isPrefix : List comparable -> Trie comparable a -> Basics.Bool

Given a prefix, checks if there are keys that begin with that prefix.

subtrie : List comparable -> Trie comparable a -> Maybe (Trie comparable a)

Given a prefix, finds any sub-trie containing the key-value pairs where the original keys begin with that prefix. The keys in the sub-trie will only consist of the remaining portion of the key after the prefix.