Want to look up value-pairs from the left or the right?
You want the pair where
🗝️
is1
and the pair where🔑
is0
?
→ < 🔑= 0, 🗝️= 2 >
< 🔑= 2, 🗝️= 0 >
< 🔑= 1, 🗝️= 1 > ←
Going through while checking every pair, if
🗝️
is equal, then, if🔑
is equal... Ah! Here they are:
🔑 is 1 where 🗝️ is 1 and 🗝️ is 2 where 🔑 is 0
Like assoc-list,
a PairDict
allows for anything as values except for functions and things that contain functions.
type alias CasedLetter=
{ lowercase: Char
, uppercase: Char
}
casedLetters: PairDict CasedLetter Char Char
casedLetters=
PairDict.empty .lowercase .uppercase
|>PairDict.putIn { lowercase= 'a', uppercase= 'A' }
|>PairDict.putIn { lowercase= 'b', uppercase= 'B' }
|>PairDict.putIn { lowercase= 'c', uppercase= 'C' }
uppercase char=
PairDict.access .lowercase char lowerUppercaseLetters
|>Maybe.map .uppercase
empty : (pair -> left) -> (pair -> right) -> PairDict pair left right
A PairDict
with no pairs inside
fromDict : (left -> right -> pair) -> (pair -> left) -> (pair -> right) -> AssocList.Dict left right -> PairDict pair left right
Create a PairDict
from a association-Dict
. left
is the key, right
is the value.
If multiple equal keys or values are present, the value first in the Dict
is prefered (see putIn
).
lowerToUpperLetters=
AssocList.empty
|>AssocList.insert 'a' 'A'
|>AssocList.insert 'b' 'B'
lowerUpperLetters=
PairDict.fromDict
(\k v-> { lowercase= k, uppercase= v })
.lowercase .uppercase
lowerToUpperLetters
fromList : (pair -> left) -> (pair -> right) -> List pair -> PairDict pair left right
Create a PairDict
conveniently from pairs.
If right or left values are given multiple times, the value first in the List
is prefered (see putIn
).
PairDict.fromList
[ { lowercase= 'b', uppercase= 'B' } --put in
, { lowercase= 'a', uppercase= 'A' } --put in
, { lowercase= 'b', uppercase= 'C' }
--ignored, as the left value already exists
, { lowercase= 'c', uppercase= 'A' }
--ignored, as the right value already exists
, { lowercase= 'c', uppercase= 'C' } --put in
]
decode : (pair -> left) -> (pair -> right) -> Json.Decode.Decoder pair -> Json.Decode.Decoder (PairDict pair left right)
A Json.Decode.Decoder
for PairDict
s encoded by encodePair
.
The order of insertion is not reconstructed (see equal
)
type alias NamedNumber=
{ number: Int
, name: String
}
decodeNamedNumber=
Decode.map NamedNumber
(\{ number, name }->
Decode.object
[ ( "number", Decode.int number )
, ( "name", Decode.string name )
]
)
"""
[
{
\"left\": 2,
\"right\": "two"
},
{
\"left\": 1,
\"right\": "one"
}
]
"""
|>Decode.decodeString
(PairDict.decode .number .name
decodeNamedNumber
)
Ok (Pairs [ { number= 1, name= "one" }, { number= 2, name= "two" } ])
= aPairDict
equal : PairDict pair leftA rightA -> PairDict pair leftB rightB -> Basics.Bool
using built-in (==) equality is often not useful in the context of association-dicts.
Do these 2 PairDict
s have the same size and identical pairs (ignoring insertion order)?
letterCodes=
PairDict.fromList .letter .code
[ { letter= 'a', code= 97 }
, { letter= 'b', code= 98 }
]
fancyCompetingLetterCodes=
PairDict.empty .code .letter
|>PairDict.putIn { code= 98, letter= 'b' }
|>PairDict.putIn { code= 97, letter= 'a' }
PairDict.equal
letterCodes
fancyCompetingLetterCodes
True
access : (pair -> key) -> key -> PairDict pair left right -> Maybe pair
Just
the pair in which key
is present in the PairDict
,
if no pair with the key
is found Nothing
.
casedLetters=
PairDict.empty .lowercase .uppercase
|>PairDict.putIn { lowercase= 'a', uppercase= 'A' }
|>PairDict.putIn { lowercase= 'b', uppercase= 'B' }
lowercase char=
PairDict.access .uppercase char
casedLetters
|>Maybe.map .lowercase
uppercase char=
PairDict.access .lowercase char
casedLetters
|>Maybe.map .uppercase
Note: If accessKey
is neither accessLeft
or accessRight
(see empty
, fromList
, fromDict
),
access
will find the most recently inserted value where key
is equal in the pair.
PairDict.empty .lowercase .uppercase
|>PairDict.putIn { inAlphabet= 0, lowercase= 'a', uppercase= 'A' }
|>PairDict.putIn { inAlphabet= 1, lowercase= 'b', uppercase= 'B' }
|>PairDict.access .inAlphabet 1
{ inAlphabet= 1, lowercase= 'b', uppercase= 'B' }
emptyOrMore : { ifEmpty : result, ifMore : pair -> PairDict pair left right -> result } -> PairDict pair left right -> result
ifEmpty
if the PairDict
contains no pairs,
else ifMore
with the most recently putIned pair followed by a PairDict
with the other pairs.
It has a very similar use case to a case
.. of
on a List
.
isEmpty=
PairDict.emptyOrMore
{ ifEmpty= True
, ifMore= \_ _-> False
}
mostRecent=
PairDict.emptyOrMore
{ ifMore= \pair _-> Just pair
, ifEmpty= Nothing
}
removeMostRecent pairDict=
pairDict
|>PairDict.emptyOrMore
{ ifMore= \_ rest-> rest
, ifEmpty= pairDict
}
size : PairDict pair left right -> Basics.Int
How many pairs there are in a PairDict
.
PairDict.fromList .number .following
(List.map (\i-> { number= i, following= i+1 })
(List.range 0 41)
)
|>PairDict.size
42
putIn : pair -> PairDict pair left right -> PairDict pair left right
Put in a pair.
If either value is already present, the PairDict
is unchanged.
specialCasedA=
{ lowercase= 'a', uppercase= 'A', inAphabet= 0 }
casedBadB=
{ lowercase= 'b', uppercase= 'B', inAlphabet= 0 }
PairDict.empty .lowercase .uppercase --lowercase and uppercase are unique across each pair
|>PairDict.putIn casedBadB --put in
|>PairDict.putIn specialCasedA --put in, because inAlphabet isn't checked
|>PairDict.putIn { lowercase= 'b', uppercase= 'C' }
--ignored, the left value already exists
|>PairDict.putIn { lowercase= 'c', uppercase= 'A' }
--ignored, the right value already exists
|>PairDict.putIn { lowercase= 'c', uppercase= 'C' } --put in
union : PairDict pair left right -> PairDict pair left right -> PairDict pair left right
Combine 2 PairDict
s, so that the pairs in toInsert
are put into preferred
.
If a value on the left or right is present, prefer the last PairDict
(see putIn
).
numberNamedOperators=
PairDict.fromList
[ { operator= '+', name= "plus" }
, { operator= '-', name= "minus" }
]
customNamedOperators=
PairDict.fromList
[ { operator= '∧', name= "and" }
, { operator= '∨', name= "or" }
, { operator= '-', name= "negate" }
]
validNamedOperators=
PairDict.union
custumNamedOperators --has a '-' left
numberOperatorNames --preferred → its '-'-pair is put in
remove : (pair -> key) -> key -> PairDict pair left right -> PairDict pair left right
Remove the left-right pair at left
.
If the value does not exist, the PairDict
is unchanged
openClosedBrackets=
PairDict.empty .open .closed
|>PairDict.putIn { open= "(", closed= ")" }
openClosedBrackets
|>PairDict.remove .open ")"
--unchanged, ")" is not a open value
|>PairDict.remove .open "("
PairDict.empty
openClosedBrackets
|>PairDict.remove .closed "("
--unchanged, "(" is not a closed value
|>PairDict.remove .closed ")"
PairDict.empty
Notice: If you don't specify accessValue
as left
or right
, it acts as a normal filter
PairDict.empty .open .closed
|>PairDict.putIn { open= "(", closed= ")", meaning= Nothing }
|>PairDict.putIn { open= "[", closed= "]", meaning= Just (List Element) }
|>PairDict.putIn { open= "<, closed= ">", meaning= Nothing }
|>PairDict.remove .meaning Nothing
values : (pair -> value) -> PairDict pair left right -> List value
Values on the pairs.
brackets=
PairDict.fromList .open .closed
[ { open= '(', closed= ')' }
, { open= '{', closed= '}' }
]
open= values .open brackets
closed= values .closed brackets
fold : (pair -> acc -> acc) -> acc -> PairDict pair left right -> acc
Reduce the left-right pairs from most recently putIned to least recently putIned.
A fold in the other direction doesn't exist, as association-Dict
s should rarely rely on order (see equal
).
brackets=
PairDict.empty
|>PairDict.putIn ( '(', ')' )
|>PairDict.putIn ( '{', '}' )
openingAndClosing=
brackets
|>PairDict.fold
(\( left, right ) acc->
acc++[ String.fromList [ left, right ] ]
)
[]
[ "{}", "()" ]
map : (pair -> resultPair) -> (resultPair -> resultLeft) -> (resultPair -> resultRight) -> PairDict pair left right -> PairDict resultPair resultLeft resultRight
Map pairs. Take a look at pair's map operations.
digitNames=
PairDict.empty .number .name
|>PairDict.putIn { number= 0, name= "zero" }
|>PairDict.putIn { number= 1, name= "one" }
mathSymbolNames=
digitNames
|>PairDict.map .symbol .name
(\{ number, name }->
{ symbol= String.fromInt number, name= name }
)
|>PairDict.putIn { symbol= "+", name= "plus" }
toDict : PairDict pair left right -> AssocList.Dict left right
Convert a PairDict
to an association-Dict
, which you can access only from the left.
casedLetters=
PairDict.fromList .lowercase .uppercase
[ { uppercase= 'A', lowercase= 'a' }
, { uppercase= 'B', lowercase= 'b' }
]
lowerFromUpper=
PairDict.toDict casedLetters
encode : (pair -> Json.Encode.Value) -> PairDict pair left right -> Json.Encode.Value
Convert a PairDict
to a Json.Encode.Value
.
somePairDict=
PairDict.empty
|>PairDict.putIn ( 1, 11 )
|>PairDict.putIn ( 2, 22 )
Encode.encode 1
(PairDict.encode
Encode.int Encode.int
somePairDict
)
"""
[
{
\"left\": 2,
\"right\": 22
},
{
\"left\": 1,
\"right\": 11
}
]
"""