An efficient implementation of persistent ordered maps from keys to values based on AVL trees.
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property.
Lookup, insertion, and deletion all take O(log n) time in both the average and worst cases, where n is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotations.
AVL trees are height-balanced, but not weight-balanced nor μ-balanced, that is, sibling nodes can have hugely differing numbers of descendants.
Keys will always be strict, whereas values can remain un-evaluated until two values will have to be combined.
Combination of two values takes place when a mapping for an already existing key is inserted in a map. In order to prevent building up of thunks that could lead to stack overflows later, the function combining the values will be evaluated right away, and this may trigger evaluation of one or both values in turn.
The default function used by operations like insert or union is const; and this will cause evaluation of the new value. Take a look at the following example:
insert 7 undefined (insert 7 25 empty) -- will fail insert 7 42 (insert 7 undefined empty) -- will succeed insertWith (+) 7 42 (insert 7 undefined empty) -- will fail
The last expression will fail because (Num.+) needs to evaluate both arguments. OTOH, expressions like
fold (\t\v -> insertWith (+) 42 v t) empty [1..1_000_000]
will not cause stack overflow when later the value associated with 42 is actually used, nor will it need heap memory for one million thunks.
Get an empty map with Monoid.mempty or ListEmpty.empty, make a singleton one with singleton or turn an association list into a TreeMap with fromList. The more general function fromListWith allows custom handling of associations with duplicate keys.
Use insert, delete, adjust and replace. The more general form of insert is insertWith which accepts a function to combine the given value with an already existing one.
The basic function is lookup, of which member and lookupDefault are variants. The operator (!!) may be used when the existence of the keys looked for is out of the question.
Because a tree map is ordered, we can find the associations with the smallest and largest keys in logarithmic time. See findMin and findMax.
There is union, difference and intersection. More general functions unionWith and intersectionWith allow combination of the affected values.
Left folds as well as right folds are provided by foldValues and foldrValues. Variants foldWithKey and foldrWithKey allow examination not only of the value, but also of the key and they walk the tree in key order.
Frequently needed functions such as values, keys, each and size are just predefined folds for your convenience.
Create a subset of an existing map with filterValues or filterWithKey.
mapValues, mapWithKey and traverseWithKey should cover any need to transform an existing map.
Functions whose name have the With suffix take a custom function to combine two values and are thus more general than the ones without that suffix. Most often it is the case that
xxx = xxxWith const
Functions whose name have the Values suffix operate on the values of the mappings contained in the map and take an appropriate custom function as argument. The Values suffix also serves to avoid conflicts with Prelude functions (i.e. map, filter, fold, foldr).
The companions of the Values functions have the suffix WithKey and accept functions that take an extra argument for the key. The key portion of a mapping or association is always passed first, followed by the associated value.
O(1) Create a singleton map
O(n) Compute the size of the map
O(log n)
insert k v map
returns a TreeMap where k is associated with v such that
lookup k (insert k v map) = Just v
If k was already associated with some value in map, then v will get evaluated to WHNF, otherwise it is left alone.
O(log n)
insertWith f k v m
If m does not contain k, this works like insert. Otherwise, the existing association of k with some value v' is replaced by an association of k with the result of evaluating
f v v'
in the resulting map.
Strict evaluation is necessary to prevent building up of large thunks of the form
f v3 (f v2 (f v1 v0))
Note that
insert = insertWith const
and that this will evaluate the new value in case of an update. If you want to prevent this, use
replace k v = insert k v . delete k
The replaced value will be evaluated only if the given function is strict in the second argument. Since const is lazy in the second argument, the following will be fine:
insert "foo" 7 (insert "foo" undefined (delete "foo" m))
That is, the value that is inserted for a given key first is not evaluated on insertion, and only evaluated on update if the update function demands it, which is not the case for a plain insert.
O(log n)
delete k tm
is a HashMap m such that
lookup k m = Nothing
and for any other key o
lookup o m = lookup o tm
Less formally, the association of k with some value, if any, is removed in the result, while all other associations are retained.
If tm didn't contain k in the first place,
delete k tm = tm
O(log n)
lookup k m
If k is associated with some value v in map m, it returns
Just v
and otherwise
Nothing
O(log n)
Find the minimum element in the tree. For empty trees, this is Maybe.Nothing.
O(log n)
Find the maximum element in the tree. For empty trees, this is Maybe.Nothing.
O(log n)
Checks whether the key is present in the map
O(log n)
Return the value to which the specified key is mapped, or the default value if this map contains no mapping for the key.
O(log n)
Return the value associated with the given key in the map. Fails with error if the key is not present.
O(log n)
Adjust the value tied to a given key in this map only if it is present. Otherwise, leave the map alone.
O(log n)
replace k v m = insert k v . delete k $ m
Insert or update the association of k with v in m but avoid evaluation of v even if m already contains k.
See also notes concerning updates on function insertWith.
O(m*log n)
unionWith f left right
Computes the union of two hash maps by inserting the elements of the left map into the right map.
If a key occurs in both maps, the function f provided in the first argument will be applied to the value from the left map and the right map like so:
f leftval rightval
to compute the result that goes into the resulting map.
This works in the same way as insertWith, that is, the value from the left hash map will be evaluated while the value from the right map may be evaluated only if the function demands it. However, values associated with keys that are member of only one map are left alone.
O(m*log n)
Computes the union of two hash maps.
If a key occurs in both maps, the value from the left map will be evaluated and taken over to the new map.
Because
union = unionWith const
the considerations concerning strictness apply for union in the same way as for unionWith.
The union of all TreeMaps in a list.
O(n)
foldValues f a map
applies the operation f to the values in the map in no particular order.
O(n)
foldWithKey f a map
applies the operation f to the keys and values in the map using the left identity a as starting value from the left in ascending key order.
f (f (f a k0 v0) k1 v1) kn vn
O(n)
foldrValues f a map
applies the operation f to the values in the map in no particular order.
O(n)
foldrWithKey f a map
applies the operation f to the keys and values in the map using the right identity a as starting value from the right in descending key order:
f k0 v0 (f k1 v1 (f kn vn a))
O(n)
Transform a map by applying a function to every value.
O(n)
Transform a map by applying a function to every key and its associated value.
O(n)
Transform a map by applying an applicative functor to every key and its associated value.
O(n)
Filter a map, retaining only mappings whose key and value satisfy a given predicate.
O(n)
Filter a map, retaining only mappings whose value satisfies a given predicate.
O(n*log m)
Computes the difference of two maps.
Returns a map that contains the mappings of the first map whose keys do not exist in the second.
O(n*log m)
Computes the intersection of two maps.
Return a map that contains the mappings of the first map for keys that also exist in the second.
O(n*log m)
Computes the intersection of two maps, combining the values with a given function.
O(n)
Build a map from an association list. If the list contains duplicate mappings, the later mappings take precedence.
O(n)
Build a map from an association list. Uses the provided function to merge values associated with duplicate keys.
produces a list of the values in the map, in no particular order.
produces the key/value pairs of a map sorted by key
produces the keys of the map in ascending order
short for Node 1 Nil Nil k v
the empty tree
O(log n)
tm.delete k
Variant of delete that is better suited for left folds and supports dot-notation
foldL o f a map
Fold a tree by applying an operation to an accumulator and key and value of every node, whereby the nodes are visited in a certain order specified by the first argument. Let the tree be
root / \ / \ left right
then the result is:
foldR o f a map
Like TreeMap.foldL, but the function is right associative.
The following yields the key of map in ascending order:
foldR Gt (\k\v\a → k:a) [] map
access field höhe
O(log n)
tm.insert k v
Variant of insert that is better suited for left folds and supports dot-notation.
version of insert that is optimized for Int keys
do the dirty work for insert operations
access field key
access field left
version of lookup that is optimised for Int keys
version of lookup that is optimised for String keys
access field right
access field value
TreeMap can be used as array element
inherited from ArrayElement.arrayFromIndexList
inherited from ArrayElement.arrayFromIndexListST
inherited from ArrayElement.arrayFromList
inherited from ArrayElement.arrayFromListST
inherited from ArrayElement.arrayFromMaybeList
inherited from ArrayElement.arrayFromMaybeListST
inherited from ArrayElement.arrayLength
inherited from ArrayElement.elemAt
inherited from ArrayElement.getAt
inherited from ArrayElement.getElemAt
inherited from ArrayElement.itemAt
inherited from ArrayElement.listFromArray
inherited from ArrayElement.maybeListFromArray
inherited from ArrayElement.modifyAt
inherited from ArrayElement.modifyElemAt
inherited from ArrayElement.newArray
inherited from ArrayElement.setAt
inherited from ArrayElement.setElemAt
inherited from Monoid.mconcat
inherited from Monoid.mtimes
inherited from Semigroup.sconcat
inherited from Semigroup.stimes
inherited from Show.display
Function generated for derived instance.
inherited from Show.showChars
inherited from Show.showList
inherited from Show.showsPrec
Function generated for derived instance.
inherited from Foldable.Foldable.fold
inherited from Foldable.Foldable.fold1
inherited from Foldable.Foldable.foldMap
inherited from Foldable.Foldable.foldMap1
inherited from Foldable.Foldable.foldl1
inherited from Foldable.Foldable.foldr1
inherited from Traversable.mapM
inherited from Traversable.sequence
inherited from Traversable.sequenceA
O(n)
Transform a map by applying a function to every value.
ListEmpty_TreeMap.null, TreeMap.has$right, TreeMap.has$key, TreeMap.has$left, TreeMap.has$value, TreeMap.has$höhe
TreeMap.rotleft, TreeMap.rotright, TreeMap.rebalance, TreeMap.leftmost, TreeMap.rightmost, TreeMap.drotlr, TreeMap.drotrl
Show_TreeMap.showsub, Show_TreeMap.display, Show_TreeMap.show
ArrayElement_TreeMap.modifyAt, ArrayElement_TreeMap.modifyElemAt