Reputation: 2563
I have a list
of dict
s like this, which I want to sort as shown below:
[{'07 PM': [{'Tuesday': 0},
{'Saturday': 0},
{'Sunday': 0},
{'Monday': 0},
{'Thursday': 0},
{'Wednesday': 0},
{'Friday': 0}]},
{'08 PM': [{'Saturday': 0},
{'Tuesday': 0},
{'Monday': 0},
{'Sunday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Wednesday': 0}]},
{'05 PM': [{'Saturday': 0},
{'Sunday': 0},
{'Monday': 0},
{'Thursday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Friday': 0}]},
{'09 PM': [{'Tuesday': 0},
{'Saturday': 0},
{'Monday': 0},
{'Sunday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Wednesday': 0}]},
Desired output:
[{'01 AM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0},
]},
{'02 AM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0},
]},
{'03 AM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0},
]},
]
That is I want it sorted by hour (24 hour format) and also by weekdays. Sorting lexographically would not work out in this case, so I tried passing a key
parameter to sorted()
, where key
was in the correct order that I wanted:
sorted(my_unsorted_data, key=sorted_data.index)
where sorted_data
was the desired output above, but got this error:
{'07 PM': [{'Tuesday': 0}, {'Saturday': 0}, {'Sunday': 0}, {'Monday': 0}, {'Thursday': 0}, {'Wednesday': 0}, {'Friday': 0}]} is not in list
.
Upvotes: 1
Views: 920
Reputation: 54263
In order to sort your list of dicts with weekdays, you could define a dict with week days as keys and id as values :
wday_numbers = {
'Sunday': 0,
'Monday': 1,
'Tuesday': 2,
'Wednesday': 3,
'Thursday': 4,
'Friday': 5,
'Saturday': 6
}
dicts = [{'Tuesday': 0},
{'Saturday': 0},
{'Monday': 0},
{'Sunday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Wednesday': 0}]
print(sorted(dicts, key=lambda x: wday_numbers[list(x.keys())[0]]))
# [{'Sunday': 0}, {'Monday': 0}, {'Tuesday': 0}, {'Wednesday': 0}, {'Thursday': 0}, {'Friday': 0}, {'Saturday': 0}]
You could write a helper function which converts 03 AM
to 3
and 2 PM
to 14
:
def to_24h(hour_pm_am):
hour, pm_am = hour_pm_am.split(' ')
if pm_am == "PM":
return int(hour)+12
else:
return int(hour)
print(sorted(['07 PM', '08 AM', '03 PM', '03 AM'], key=to_24h))
# ['03 AM', '08 AM', '03 PM', '07 PM']
It's usually not a good idea to have a list of dicts with single, unique values. This list of dicts could be converted to one dict (if the order is important, to an OrderedDict).
You'll get the exact same information, but it will be much easier to retrieve information.
Here's an example :
from collections import OrderedDict
wday_numbers = {
'Sunday': 0,
'Monday': 1,
'Tuesday': 2,
'Wednesday': 3,
'Thursday': 4,
'Friday': 5,
'Saturday': 6
}
dicts = [{'Tuesday': 9},
{'Saturday': 3},
{'Monday': 2},
{'Sunday': 5},
{'Thursday': 4},
{'Friday': 7},
{'Wednesday': 1}]
pairs = [(day, number) for dct in dicts for day, number in dct.items()]
pairs.sort(key=lambda d: wday_numbers[d[0]])
ordered_days = OrderedDict(pairs)
print(ordered_days)
# OrderedDict([('Sunday', 5), ('Monday', 2), ('Tuesday', 9), ('Wednesday', 1), ('Thursday', 4), ('Friday', 7), ('Saturday', 3)])
Upvotes: 1
Reputation: 944
A more pythonic approach
days = {'Sunday':0, 'Monday':1, 'Tuesday':2, 'Wednesday':3, 'Thursday':4, 'Friday':5, 'Saturday':6}
def time_custom(val):
time = val.keys()[0]
val[time] = sorted(val[time], key=lambda x: days[x.keys()[0]])
return time
myList = sorted(myList, key=time_custom )
Upvotes: 0
Reputation: 123491
Here's my take.
Sample input data:
data = [{'07 PM': [{'Tuesday': 0},
{'Saturday': 0},
{'Sunday': 0},
{'Monday': 0},
{'Thursday': 0},
{'Wednesday': 0},
{'Friday': 0}]},
{'08 AM': [{'Saturday': 0},
{'Tuesday': 0},
{'Monday': 0},
{'Sunday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Wednesday': 0}]},
{'05 PM': [{'Saturday': 0},
{'Sunday': 0},
{'Monday': 0},
{'Thursday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Friday': 0}]},
{'09 PM': [{'Tuesday': 0},
{'Saturday': 0},
{'Monday': 0},
{'Sunday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Wednesday': 0}]},
]
Code:
WEEKDAY_RANK = dict(zip('Sunday,Monday,Tuesday,Wednesday,'
'Thursday,Friday,Saturday'.split(','), range(7)))
def time_to_24(time_of_day):
hour, am_pm = time_of_day.split()
return int(hour) + (0 if am_pm == 'AM' else 12)
desired = []
for d in sorted(data, key=lambda d: time_to_24( d.items()[0][0] )):
time_of_day, values = d.items()[0]
values.sort(key=lambda d: WEEKDAY_RANK[ d.items()[0][0] ])
desired.append({time_of_day: values})
from pprint import pprint
pprint(desired)
Output:
[{'08 AM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0}]},
{'05 PM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0}]},
{'07 PM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0}]},
{'09 PM': [{'Sunday': 0},
{'Monday': 0},
{'Tuesday': 0},
{'Wednesday': 0},
{'Thursday': 0},
{'Friday': 0},
{'Saturday': 0}]}]
Upvotes: 0
Reputation: 78750
The outer dictionaries in your lists only have one key each in the format of a number followed by 'AM'
or 'PM
. To sort the outer dictionaries, we can define the sort-key
def sortouter(dic):
hour_str = dic.keys()[0] # list(dic.keys())[0] in Python 3
hour, am_pm = hour_str.split()
return (am_pm, int(hour))
Assuming your list is named dicts
, apply by issueing
dicts.sort(key=sortouter)
This will sort by 'AM'
/'PM'
first (coincidally, 'AM' comes before 'PM' lexicographically) and by numeric value of the hour second.
In order to sort each inner list, loop over your list of dictionaries and sort each of these lists by the only key (the weekday) they have. Of course, we need another sortkey to order the weekdays.
def sortinner(dic):
day = dic.keys()[0] # Python 3: list(dic.keys())[0]
return {'Sunday': 0, 'Monday': 1, ..., 'Saturday': 7}[day]
The loop:
for dic in dicts:
for lst in dic.values(): # only one iteration with your current format
lst.sort(key=sortinner)
your solution works can you please explain how sortouter works in little more detail
When you call dicts.sort(key=sortouter)
the dictionaries in the list dicts
get passed to sortouter
(parameter named dic
).
The first line of the function simply gets the only key in each of the dictionaries in dicts
, for example '02 AM'
.
The second line splits the string by the blank and - sticking to the example - assigns '02'
to the name hour
and 'AM'
to the name am_pm
.
Finally the sort-key that is returned is the tuple ('AM', 2)
.
Now, Python will sort the list of dictionaries as if it was a list of (AM/PM, integer) tuples (sorting something as if it looked like something else is the whole idea behind a sort-key).
Tuples are sorted lexicographically like strings, i.e. for two tuples t
and s
the tuple t
is smaller than s
if t[0] < s[0]
. If t[0] == s[0]
then the next elements, t[1]
and s[1]
are compared, and so on.
Thus, since 'AM'
< 'PM'
(because 'A'
< 'P
') all 'AM'
-dicts come before the 'PM'
-dicts (Python does not even have to look at the integer in the return value of sortouter
to make that decision). Within the group of either all 'AM'
- or 'PM'
-dicts, the second element of the tuple sortouter
returns gets compared (since the first element is the same), so the dictionaries get sorted by ascending hour.
Upvotes: 1