skyqrose / assoc-list-extra / AssocList.Extra

Convenience functions for working with AssocList.Dict

A copy of Dict.Extra that works on AssocList.Dict instead of the Dict implementation from elm/core.

List operations

groupBy : (v -> k) -> List v -> AssocList.Dict k (List v)

Takes a key-fn and a list. Creates a Dict which maps the key to a list of matching elements.

import AssocList as Dict

groupBy String.length [ "tree" , "apple" , "leaf" ]
--> Dict.fromList [ ( 4, [ "tree", "leaf" ] ), ( 5, [ "apple" ] ) ]

filterGroupBy : (v -> Maybe k) -> List v -> AssocList.Dict k (List v)

Takes a key-fn and a list. Creates a Dict which maps the key to a list of matching elements, skipping elements where key-fn returns Nothing

import AssocList as Dict

filterGroupBy (String.uncons >> Maybe.map Tuple.first) [ "tree" , "", "tweet", "apple" , "leaf", "" ]
--> Dict.fromList [ ( 't', [ "tree", "tweet" ] ), ( 'a', [ "apple" ] ), ( 'l', [ "leaf" ] ) ]

filterGroupBy
    .car
    [ { name = "Mary"
      , car = Just "Ford"
      }
    , { name = "Jack"
      , car = Nothing
      }
    , { name = "Jill"
      , car = Just "Tesla"
      }
    , { name = "John"
      , car = Just "Tesla"
      }
    ]
--> Dict.fromList
--> [ ( "Ford"
-->   , [ { name = "Mary" , car = Just "Ford" } ]
-->   )
--> , ( "Tesla"
-->   , [ { name = "Jill" , car = Just "Tesla" }
-->     , { name = "John" , car = Just "Tesla" }
-->     ]
-->   )
--> ]

fromListBy : (v -> k) -> List v -> AssocList.Dict k v

Create a dictionary from a list of values, by passing a function that can get a key from any such value. If the function does not return unique keys, earlier values are discarded.

import AssocList as Dict

fromListBy String.length [ "tree" , "apple" , "leaf" ]
--> Dict.fromList [ ( 4, "leaf" ), ( 5, "apple" ) ]

fromListDedupe : (v -> v -> v) -> List ( k, v ) -> AssocList.Dict k v

Like Dict.fromList, but you provide a way to deal with duplicate keys. Create a dictionary from a list of pairs of keys and values, providing a function that is used to combine multiple values paired with the same key.

import AssocList as Dict

fromListDedupe
    (\a b -> a ++ " " ++ b)
    [ ( "class", "menu" ), ( "width", "100%" ), ( "class", "big" ) ]
--> Dict.fromList [ ( "class", "menu big" ), ( "width", "100%" ) ]

fromListDedupeBy : (v -> v -> v) -> (v -> k) -> List v -> AssocList.Dict k v

fromListBy and fromListDedupe rolled into one.

import AssocList as Dict

fromListDedupeBy (\first second -> first) String.length [ "tree" , "apple" , "leaf" ]
--> Dict.fromList [ ( 4, "tree" ), ( 5, "apple" ) ]

frequencies : List k -> AssocList.Dict k Basics.Int

Count the number of occurences for each of the elements in the list.

import AssocList as Dict

frequencies [ "A", "B", "C", "B", "C", "B" ]
--> Dict.fromList [ ( "A", 1 ), ( "B", 3 ), ( "C", 2 ) ]

Manipulation

removeWhen : (k -> v -> Basics.Bool) -> AssocList.Dict k v -> AssocList.Dict k v

Remove elements which satisfies the predicate.

import AssocList as Dict

Dict.fromList [ ( "Mary", 1 ), ( "Jack", 2 ), ( "Jill", 1 ) ]
    |> removeWhen (\_ value -> value == 1 )
--> Dict.fromList [ ( "Jack", 2 ) ]

removeMany : AssocSet.Set k -> AssocList.Dict k v -> AssocList.Dict k v

Remove a key-value pair if its key appears in the set.

import AssocList as Dict
import AssocSet as Set

Dict.fromList [ ( "Mary", 1 ), ( "Jack", 2 ), ( "Jill", 1 ) ]
    |> removeMany (Set.fromList [ "Mary", "Jill" ])
--> Dict.fromList [ ( "Jack", 2 ) ]

keepOnly : AssocSet.Set k -> AssocList.Dict k v -> AssocList.Dict k v

Keep a key-value pair if its key appears in the set.

import AssocList as Dict
import AssocSet as Set

Dict.fromList [ ( "Mary", 1 ), ( "Jack", 2 ), ( "Jill", 1 ) ]
    |> keepOnly (Set.fromList [ "Jack", "Jill" ])
--> Dict.fromList [ ( "Jack", 2 ), ( "Jill", 1 ) ]

insertDedupe : (v -> v -> v) -> k -> v -> AssocList.Dict k v -> AssocList.Dict k v

Insert an element at the given key, providing a combining function that used in the case that there is already an element at that key. The combining function is called with original element and the new element as arguments and returns the element to be inserted.

import AssocList as Dict

Dict.fromList [ ( "expenses", 38.25 ), ( "assets", 100.85 ) ]
    |> insertDedupe (+) "expenses" 2.50
    |> insertDedupe (+) "liabilities" -2.50
--> Dict.fromList [ ( "expenses", 40.75 ), ( "assets", 100.85 ), ( "liabilities", -2.50 ) ]

mapKeys : (k1 -> k2) -> AssocList.Dict k1 v -> AssocList.Dict k2 v

Apply a function to all keys in a dictionary.

import AssocList as Dict

Dict.fromList [ ( 5, "Jack" ), ( 10, "Jill" ) ]
    |> mapKeys (\x -> x + 1)
--> Dict.fromList [ ( 6, "Jack" ), ( 11, "Jill" ) ]

Dict.fromList [ ( 5, "Jack" ), ( 10, "Jill" ) ]
    |> mapKeys String.fromInt
--> Dict.fromList [ ( "5", "Jack" ), ( "10", "Jill" ) ]

filterMap : (k -> v1 -> Maybe v2) -> AssocList.Dict k v1 -> AssocList.Dict k v2

Apply a function that may or may not succeed to all entries in a dictionary, but only keep the successes.

import AssocList as Dict

let
    isTeen n a =
        if 13 <= n && n <= 19 then
            Just <| String.toUpper a
        else
            Nothing
in
Dict.fromList [ ( 5, "Jack" ), ( 15, "Jill" ), ( 20, "Jones" ) ]
    |> filterMap isTeen
--> Dict.fromList [ ( 15, "JILL" ) ]

invert : AssocList.Dict a b -> AssocList.Dict b a

Inverts the keys and values of an array.

import AssocList as Dict

Dict.fromList [ ("key", "value")  ]
    |> invert
--> Dict.fromList [ ( "value", "key" ) ]

Utilities

any : (k -> v -> Basics.Bool) -> AssocList.Dict k v -> Basics.Bool

Determine if any key/value pair satisfies some test.

import AssocList as Dict

Dict.fromList [ ( 9, "Jill" ), ( 7, "Jill" ) ]
    |> any (\_ value -> value == "Jill")
--> True

Dict.fromList [ ( 9, "Jill" ), ( 7, "Jill" ) ]
    |> any (\key _ -> key == 5)
--> False

find : (k -> v -> Basics.Bool) -> AssocList.Dict k v -> Maybe ( k, v )

Find the first key/value pair that matches a predicate.

import AssocList as Dict

Dict.fromList [ ( 9, "Jill" ), ( 7, "Jill" ) ]
    |> find (\_ value -> value == "Jill")
--> Just ( 7, "Jill" )

Dict.fromList [ ( 9, "Jill" ), ( 7, "Jill" ) ]
    |> find (\key _ -> key == 5)
--> Nothing