Sorting Associations by DayName (day of week) using KeySort and/or KeySortBy

I have an association where the keys are the days of the week:

  assoc = <|Wednesday -> 122150, Thursday -> 119450, Friday -> 124350,
Saturday -> 92000, Sunday -> 85800, Monday -> 107900,
Tuesday -> 116500|>


I would like to sort it by day of week, with the usual ordering (Sunday, Monday, Tuesday....)

How would I do this using KeySort or KeySortBy? I've tried these, and none of them work:

KeySortBy[assoc, DayName]
KeySortBy[assoc, DateValue]
KeySortBy[assoc, Greater]


Perhaps the fact that Greater works for dates (see below) but not for day names means that MMA doesn't recognize Sunday, Monday, Tuesday... as canonical ordering for day names.

Thus far, my only solution is to manually reconstruct the association with the proper ordering:

Association[{Sunday -> assoc[Sunday], Monday -> assoc[Monday]},
Tuesday -> assoc[Tuesday], Wednesday -> assoc[Wednesday],
Thursday -> assoc[Thursday], Friday -> assoc[Friday],
Saturday -> assoc[Saturday]]


<|Sunday -> 85800, Monday -> 107900, Tuesday -> 116500, Wednesday -> 122150, Thursday -> 119450, Friday -> 124350, Saturday -> 92000|>

Note that KeySortBy can be used where the keys are dates:

assoc2 = <|{2020, 1, 2} -> 3200, {2020, 1, 3} -> 3700, {2020, 1, 5} ->
2400, {2020, 1, 6} -> 3550, {2020, 1, 7} -> 4550, {2020, 1, 4} ->
2250, {2020, 1, 1} -> 2200, {2020, 1, 8} -> 3650, {2020, 1, 10} ->
4700, {2020, 1, 9} -> 4050|>

assoc3 = <|DateObject@{2020, 1, 2} -> 3200,
DateObject@{2020, 1, 3} -> 3700, DateObject@{2020, 1, 5} -> 2400,
DateObject@{2020, 1, 6} -> 3550, DateObject@{2020, 1, 7} -> 4550,
DateObject@{2020, 1, 4} -> 2250, DateObject@{2020, 1, 1} -> 2200,
DateObject@{2020, 1, 8} -> 3650, DateObject@{2020, 1, 10} -> 4700,
DateObject@{2020, 1, 9} -> 4050|>


Both of these give the proper ordering:

KeySortBy[assoc2, Greater]
KeySortBy[assoc3, Greater]


UPDATE

Given that the days of the week (Sunday, Monday, Tuesday...) are system-defined entities, I was curious whether MMA would have a built-in rule that could be used, in combination with KeySortBy, to order them in the usual way (or one of the usual ways). [Something whose form looked like KeySortBy[assoc, Greater] or KeySortBy[assoc, ISOWeekDay], neither of which work.]

Based on the answers kindly provided by kglr, creidhne, and Daniel Huber, I now understand that's not the case. Their answers all rely on first creating a rule explicitly showing the desired ordering (e.g., <|Sunday -> 1, Monday -> 2, Tuesday -> 3,....), and then sorting based on that rule using KeySortBy.

Using KeySortBy, kglr came up with the simplest syntax:

KeySortBy[PositionIndex[SystemDateObjectDump$DaysOfTheWeek]] @ assoc  so I've accepted his as the answer. Having said that, given that one always needs to feed MMA the explict ordering anyways, it seems the simplest syntax of all would be obtained using KeyTake instead of KeySortBy: KeyTake[assoc, SystemDateObjectDump$DaysOfTheWeek]


<|Sunday -> 85800, Monday -> 107900, Tuesday -> 116500, Wednesday -> 122150, Thursday -> 119450, Friday -> 124350, Saturday -> 92000|>

dayNameToISOWeekDay = DateValue[DayRound[{2021, 1}, #], "ISOWeekDay"] &;

KeySortBy[dayNameToISOWeekDay] @ assoc

 <|Monday -> 107900, Tuesday -> 116500, Wednesday -> 122150,
Thursday -> 119450, Friday -> 124350, Saturday -> 92000,
Sunday -> 85800|>


Update: To have the week start from Sunday:

isoWeekDay = DateValue[{ToString @ #, {"DayName"}}, "ISOWeekDay"] &;

KeySortBy[isoWeekDay] @ assoc

 <|Sunday -> 85800, Monday -> 107900, Tuesday -> 116500,
Wednesday -> 122150, Thursday -> 119450, Friday -> 124350,
Saturday -> 92000|>


Alternatively,

KeySortBy[PositionIndex[SystemDateObjectDump$DaysOfTheWeek]] @ assoc   <|Sunday -> 85800, Monday -> 107900, Tuesday -> 116500, Wednesday -> 122150, Thursday -> 119450, Friday -> 124350, Saturday -> 92000|>  • Interesting approach! You used DayRound to convert the DOW (day of week) to a DateObject of arbitrary date that contained that DOW, and then used DateValue + "ISOWeekDay" to convert the DOW to an integer. Alas, MMA's implementation of "ISOWeekDay" starts with Monday instead of Sunday! This is the same as Python's (pythontic.com/datetime/date/isoweekday), but is contrary to MMA's own documentation, which has Wed = 4 (reference.wolfram.com/language/ref/DateString.html). To fix this, I did: dayNameToISOWeekDay = Mod[DateValue[DayRound[{2021, 1}, #], "ISOWeekDay"], 7] &; – theorist May 8 at 2:49 • @theorist, please see the update. – kglr May 8 at 3:59 • Given that one always needs to feed MMA the explict ordering anyways, it seems the simplest syntax of all would be obtained using KeyTake instead of KeySortBy: KeyTake[assoc, SystemDateObjectDump$DaysOfTheWeek] [See update at end of my question] – theorist May 8 at 23:37

You could define a function, to be used by "SortBy", that determines the ordering. E.g.:

assoc = <|Wednesday -> 122150, Thursday -> 119450, Friday -> 124350,
Saturday -> 92000, Sunday -> 85800, Monday -> 107900,
Tuesday -> 116500|>

by[day_] =
Switch[day, Sunday, 1, Monday, 2, Tuesday, 3, Wednesday, 4,
Thursday, 5, Friday, 6, Saturday, 7];

KeySortBy[assoc, by]


• Thanks, that works. But I was hoping to directly leverage the fact that Mathematica recognizes DayNames to create something simpler, like what I'm able to do for dates (e.g., KeySortBy[assoc2, Greater]) – theorist May 7 at 19:31

The canonical sort of the values returned by DayName is alphabetic, so the Greater parameter sorts as Friday-to-Wednesday in alphabetical order.

We can use an association to map the day names to the Sunday-to-Saturday sort order. The association avoids the need to use a function with sort functions. Here are two ways to create the association.

daynameOrder = AssociationThread[DayName/@Tuples[{{0}, {0}, Range[5, 11]}], Range[7]];


To sort an association with KeySortBy, use:

assoc = <|Wednesday -> 122150, Thursday -> 119450, Friday -> 124350,
Saturday -> 92000, Sunday -> 85800, Monday -> 107900,
Tuesday -> 116500|>;

KeySortBy[daynameOrder] @ assoc


or

KeySortBy[assoc, daynameOrder]


<| Sunday->85800, Monday->107900, Tuesday->116500, Wednesday->122150, Thursday->119450, Friday->124350, Saturday->92000 |>

An alternative to using SortBy[..., f] is to create a dedicated ordering function, which then can be used in any sorting operation. For example, let us write a WeekOrder function, from Monday to Sunday:

weekdays = {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};
Do[WeekOrder[weekdays[[i]], weekdays[[j]]] = Order[i, j], {i, 7}, {j, 7}]


Then we can do

assoc = <|Wednesday -> 122150, Thursday -> 119450, Friday -> 124350, Saturday -> 92000, Sunday -> 85800, Monday -> 107900, Tuesday -> 116500|>;

In[]:= KeySort[assoc, WeekOrder]
Out[]= <|Monday -> 107900, Tuesday -> 116500, Wednesday -> 122150, Thursday -> 119450, Friday -> 124350, Saturday -> 92000, Sunday -> 85800|>


WeekOrder can also be used with Ordering:

In[]:= Ordering[Keys[assoc], 2, WeekOrder]
Out[]= {6, 7}


or any other sorting function:

In[]:= OrderedQ[{Monday, Sunday}, WeekOrder]
Out[]= True


For example, this will place all Mondays first, then all Tuesdays, etc:

SortBy[DateRange[Today, Today + Quantity[1, "Month"]], DayName, WeekOrder]