I think you can do something like comparableA -> comparableB -> comparableC. I’m curious as to what you’re planning on comparing that could be different though.
Thanks.
I’m still working with my idiotic datastructure for dates (first level for years, second level for months, third level for days, fourth level for names, ok it would be simpler to do a single level and index simply with dates, but at least that’s a good exercise. And I want to be able to easily regroup the items by years or months so at least that will be easy.)
{
2021: {
8: {
31: {"Jeremy": 1}
},
9: {
7: {"Jane": 5},
10: {"Sandra": 5},
12: {"Michel": 2, "Pedro": 2}
}
}
}
type alias Achievements =
Dict Int (Dict Int (Dict Int (Dict String Int)))
To be able to iterate over the dates in order I wrote a function that can turn a dict of dicts into a dict indexed by pairs of the keys.
shallowDict : Dict comparable (Dict comparable1 c) -> Dict ( comparable, comparable1 ) c
shallowDict dct =
dct
|> Dict.toList
|> List.map
(\( kA, subDict ) ->
( kA, subDict |> Dict.toList )
)
|> List.map
(\( kA, subList ) ->
subList |> List.map (\( kB, vC ) -> ( ( kA, kB ), vC ))
)
|> List.concat
|> Dict.fromList
indexedMap : (Int -> Int -> Int -> String -> Int -> a) -> Achievements -> List a
indexedMap func achievements =
achievements
|> shallowDict
|> shallowDict
|> shallowDict
|> Dict.toList
|> List.map
(\( ( ( ( year, month ), day ), name ), countValue ) ->
func year month day name countValue
)
Wouldn’t it be more idiomatic Elm to use custom data types that describe your application structure precisely?
Something along the lines of
type alias Score = Int
type alias User = String
type alias PerUserScore = (User, Score)
-- Three-level grouping hierarchy
-- This could be a separate module with appropriate
-- transformation functions
type Day a = Day Int (List a)
type Month a = Month Int (List (Day a))
type Year a = Year Int (List (Month a))
-- Then the equivalent of your nested-dict Achievements alias is
type Achievements a = List (Year a)
-- For different flat groupings you can introduce new types:
type DMY = DMY Int Int Int
type FlatGrouping = Daily DMY | YearMonth Int Int | Yearly Int
type PerUserAchievements = All User (List (DMY, Score))
| Grouped User (List (FlatGrouping, (List Score)))
-- Or as a record:
type alias UserAchievements =
{ user : User
-- all of user's achievements sorted by date
, achievements : List (DMY, Score)
-- or grouped yearly for this user by using JustsScore leaves
, yearly : Achievements Score
}
-- Set of functions to go with the module
fromJson : Json.Value -> LeafDecoder a -> Achievements a
monthlyForUser : Achievements PerUserScore -> User -> PerUserAchievements
...
Obviously this is just off-the-cuff without any thought put into actual application. You’d probably spend time designing your data structures with care and with your concrete application in view.
Stick that in a module, and design a set of functions to deal with setting, getting, sorting, transforming, serialization, validation to ensure dates are correct for different months, etc. Ideally, you’d design this in a way that prevents impossible states, which is not necessarily the case in this quick example.
You can go more generic, if so inclined, by designing a separate module for generic year/month/day hierarchy manipulation, etc.
The point is that you get rid of the question completely through shaping your application with data types, instead of suffering with layers of Dict (Dict (Dict ...))).
Not the answer you were looking for, but hope it still helps.