Have many keys to lookup values.
Let's compare
Dict
You want the value where the key is
1
?
0 : 🏡
--> 1 : 🏚
2 : 🏚
the key is unique among all items
Going through while comparing your key.
the value is 🏚 where the key is `1`
KeysDict
First of all, get used to some names
keepInParserPipelineOperator=
{ operator= "|=" --no operator overloading wanted!
, origin= ElmRepoPackage "parser" --is the same for |.
}
door .operator
--is a promise, that the operator value is never the same for two houses.
So... If you have a key and the type of door it could match, you can find the only matching house and enter.
You want to enter the house where
🗝️
is1
?
🔑= 0, 🏠= 🏚, 🗝️= 2
🔑= 2, 🏠= 🏡, 🗝️= 0
🔑= 1, 🏠= 🏚, 🗝️= 1 <--
🔑, 🗝️: doors you can "open" with a key unique across all houses
Going through while checking every house, if the
🗝️
matches.
🔑= 1, 🏠= 🏚, 🗝️= 1 where 🗝️ is 1
You want to enter the house where
🔑
is0
?
--> 🔑= 0, 🏠= 🏚, 🗝️= 2
🔑= 2, 🏠= 🏡, 🗝️= 0
🔑= 1, 🏠= 🏚, 🗝️= 1
🔑, 🗝️: doors you can "open" with a key unique across all houses
Going through while checking every house, if the
🔑
matches.
🔑= 0, 🏠= 🏚, 🗝️= 2 where 🔑 is 0
Unsorted data structure, which promises Uniqueness
for multiple doors.
This allows for a special kind of access:
one of many keys -> one of many doors -> house (containing the key you searched by).
Read the module doc for more!
type alias CasedLetter=
{ lowercase: Char
, uppercase: Char
}
casedLetters: KeysDict CasedLetter
casedLetters=
KeysDict.enterableBy
[ door .lowercase, door .uppercase ]
|>putUp { lowercase= 'a', uppercase= 'A' }
|>putUp { lowercase= 'b', uppercase= 'B' }
|>putUp { lowercase= 'c', uppercase= 'C' }
uppercase char=
lowerUppercaseLetters
|>enterBy { door= .lowercase, key= char }
|>Maybe.map .uppercase
enterableBy : List (Uniqueness house) -> KeysDict house
A KeysDict
with no houses inside, promising that given aspects are unique across all houses (see Uniqueness
).
equal : KeysDict house -> KeysDict house -> Basics.Bool
How can you know if each house in aKeysDict
can also be found in bKeysDict
?
letterCodes=
[ { letter= 'a', code= 97 }
, { letter= 'b', code= 98 }
]
|>List.foldl putUp
(KeysDict.enterableBy
[ door .letter, door .code ]
)
fancyCompetingLetterCodes=
KeysDict.enterableBy
[ door .code, door .letter ]
|>putUp { code= 98, letter= 'b' }
|>putUp { code= 97, letter= 'a' }
(==) letterCodes fancyCompetingLetterCodes
--> elm crashes
Because a KeysDict
's Uniqueness
is defined as functions.
(==)
(houses letterCodes)
(houses fancyCompetingLetterCodes)
--> False
Even though both contain the same houses but in a different order.
Don't use
==
to compareKeysDict
sWith non-comparable types, thinking about order doesn't make much sense. You shouldn't rely on it when using functions like folds or
houses
.
Instead, you should use
KeysDict.equal
letterCodes
fancyCompetingLetterCodes
--> True
Houses must not contain functions or json. Elm will crash trying to see if they are equal.
enterBy : { door : house -> key, key : key } -> KeysDict house -> Maybe house
Just
the house where door
of the house matches the key
;
if no such house is found, Nothing
.
casedLetters=
KeysDict.enterableBy
[ door .lowercase, door .uppercase ]
|>putUp { lowercase= 'a', uppercase= 'A' }
|>putUp { lowercase= 'b', uppercase= 'B' }
lowercase char=
casedLetters
|>enterBy { door= .uppercase, key= char }
|>Maybe.map .lowercase
uppercase char=
casedLetters
|>enterBy { door= .lowercase, key= char }
|>Maybe.map .uppercase
Note: If keys of door
aren't promised to be unique,
enterBy
will find the most recently inserted house where door
of the house matches the key
.
ratedCasedLetters=
KeysDict.enterableBy
[ door .lowercase, door .uppercase ]
|>putUp { rating= 0.5, lowercase= 'a', uppercase= 'A' }
|>putUp { rating= 0.5, lowercase= 'b', uppercase= 'B' }
enterBy { door= .rating, key= 0.5 } ratedCasedLetters
--> { rating= 0.5, lowercase= 'b', uppercase= 'B' }
countHouses : KeysDict house -> Basics.Int
How many houses there are.
List.foldl putIn
(KeysDict.enterableBy
[ door .number, door .following ]
)
(List.map (\i-> { number= i, following= i +1 })
(List.range 0 41)
)
|>countHouses
--> 42
putUp : house -> KeysDict house -> KeysDict house
Put a house into keysDict
. Keys must not contain functions or json. Elm will crash trying to see if they match.
If there is already a house with the same key is already present, (see Uniqueness
), the KeysDict
remains unchanged.
KeysDict.enterableBy
[ door .lowercase, door .uppercase ]
|>putUp { lowercase= 'b', uppercase= 'B', rating= 0.5 }
--put up
|>putUp { lowercase= 'a', uppercase= 'A', rating= 0.5 }
--put up, because rating is not a key
|>putUp { lowercase= 'b', uppercase= 'C', rating= 0 }
--ignored, the .lowercase already exists
|>putUp { lowercase= 'c', uppercase= 'A', rating= 0 }
--ignored, the .uppercase already exists
|>putUp { lowercase= 'c', uppercase= 'C', rating= 0.6 }
--put up
tearDown : { door : house -> key, key : key } -> KeysDict house -> KeysDict house
Remove the house where door
of the house matches the key
.
If the key does not exist, the KeysDict
is unchanged
openClosedBrackets=
KeysDict.enterableBy
[ door .open, door .closed ]
|>putUp { open= "(", closed= ")" }
openClosedBrackets
|>tearDown { door= .open, key= ")" }
--unchanged, ")" does not exist as a .open key
|>tearDown { door= .open, key= "(" }
--> KeysDict.enterableBy
--> [ door .open, door .closed ]
openClosedBrackets
|>tearDown { door= .closed, key= "(" }
--unchanged, "(" does not exist as a .closed key
|>tearDown { door= .closed, key= ")" }
--> KeysDict.enterableBy
--> [ door .open, door .closed ]
Notice: If there is no promise of Uniqueness
for door
, remove
acts as a normal filter.
KeysDict.enterableBy
[ door .open, door .closed ]
|>putUp { open= "(", closed= ")", meaning= Nothing }
|>putUp { open= "[", closed= "]", meaning= Just List }
|>putUp { open= "<, closed= ">", meaning= Nothing }
|>tearDown { door= .meaning, key= Nothing }
--> KeysDict.enterableBy
--> [ door .open, door .closed ]
--> |>putUp { open= "[", closed= "]", meaning= Just List }
foldHouses : (house -> acc -> acc) -> acc -> KeysDict house -> acc
Reduce the houses from most recently to least recently inserted house.
With non-comparable types, thinking about order doesn't make much sense. You shouldn't rely on it when using functions like folds or
houses
.
brackets=
KeysDict.enterableBy
[ door .open, door .closed ]
|>putUp { open= '(', closed= ')' }
|>putUp { open= '{', closed= '}' }
openingAndClosing=
brackets
|>foldHouses
(\{ open, closed }->
(::) (String.fromList [ open, closed ])
)
[]
--> []
--> |>(::) (String.fromList [ '{' '}' ])
--> |>(::) (String.fromList [ '(' ')' ])
map : (house -> resultHouse) -> List (Uniqueness resultHouse) -> KeysDict house -> KeysDict resultHouse
Map all houses.
digitNames=
KeysDict.enterableBy
[ door .number, door .name ]
|>putUp { number= 0, name= "zero" }
|>putUp { number= 1, name= "one" }
mathSymbolNames=
digitNames
|>mapHouses [ door .symbol, door .name ]
(\{ number, name }->
{ symbol= String.fromInt number, name= name }
)
|>putUp { symbol= "+", name= "plus" }
houses : KeysDict house -> List house
The List
containing all houses from most recently (= head) to least recently inserted house.
With non-comparable types, thinking about order doesn't make much sense. You shouldn't rely on it when using functions like folds or
houses
.
isEmpty=
List.isEmpty <<houses
mostRecentlyInserted=
List.head <<houses
removeMostRecentlyInserted keysDict=
case houses keysDict of
_ ::rest->
rest
[]->
keysDict
toDict : { key : house -> key, value : house -> value } -> KeysDict house -> AssocList.Dict key value
Convert a KeysDict
to an association-Dict
.
casedLetters=
KeysDict.enterableBy
[ door .lowercase, door .uppercase ]
|>putUp { uppercase= 'A', lowercase= 'a' }
|>putUp { uppercase= 'B', lowercase= 'b' }
lowerFromUppercase=
KeysDict.toDict { key= .uppercase, value= .lowercase }
casedLetters
serialize : Serialize.Codec customError house -> List (Uniqueness house) -> Serialize.Codec customError (KeysDict house)
Serialize a KeysDict
.
type alias NamedNumber=
{ name: String
, number: Int
}
namedNumberCodec=
Serialize.record NamedNumber
|>Serialize.field .name Decode.string
|>Serialize.field .number Decode.int
|>Serialize.finishRecord
namedNumberKeysDictCodec=
KeysDict.codec namedNumberCodec
[ door .number, door .name ]
someKeysDict=
KeysDict.enterableBy
[ door .number, door .name ]
|>putUp { number= 1, name= "one" }
|>putUp { number= 2, name= "two" }
Serialize.encodeToJson
(NamedNumberKeyDictCodec someKeysDict)
|>Json.Encode.encode 1
--> """
--> [
--> {
--> \"number\": 2,
--> \"name\": "two"
--> },
--> {
--> \"number\": 1,
--> \"name\": "one"
--> }
--> ]
--> """
"""
[
{
\"number\": 2,
\"name\": "two"
},
{
\"number\": 1,
\"name\": "one"
}
]
"""
|>Json.Decode.decodeString
(Serialize.decodeFromJson
namedNumberKeysDictCodec
)
--> Ok
--> (KeysDict.enterableBy
--> [ door .number, door .name ]
--> |>putUp { number= 1, name= "one" }
--> |>putUp { number= 2, name= "two" }
--> )