I have a dictionary named 'times' which maps keys to string values that represent a time:
times = {'key1': '12.23', 'key2': '43:53.29', 'key3': '1:38:11.50r'}
The string takes the form of [hours]:[minutes]:[seconds].[milliseconds][r] where every field is optional. The r is a flag that doesn't depend on any other values being filled in and doesn't factor into sorting. [hours] requires that [minutes] and down are present, but [minutes] doesn't require [hours] to be present.
I want to end up with a list of keys sorted by the time-ordering of their values.
I have the following:
standings = sorted(times, key=times.__getitem__)
but it only sorts based on a string value. I'm new to python, but if I were using java I would probably write a Time class with a custom compareTo() function to get the sort to work.
I could write a function that converts the string to a time in milliseconds, then sort based on that, but don't know how I would do so using 'key=' in the sorted() function.
import re
def as_list(time):
"""
>>> as_list('1:38:11.50r')
[1, 38, 11, 50]
>>> as_list('2.23')
[0, 0, 2, 23]
"""
# Extract times and convert to integers
times = [int(x) for x in re.split(r"[:.]", re.sub("[a-z]$", "", time))]
# If needed pad from the left side with zeros and return
return times if len(times) == 4 else [0] * (4 - len(times)) + times
[k for k, t in sorted(times.items(), key = lambda x: as_list(x[1]))]
Or even more concise way:
[key for _, key in sorted((as_list(v), k) for k, v in times.items())]
It works because lists or tuples in Python are sorted in a lexicographical order. Let's say you have list as follows:
>>> l = [[0, 1], [-1 , 2, 3], [4, 5], [0, -1]]
You can call sorted
on it
>>> sorted(l)
[[-1, 2, 3], [0, -1], [0, 1], [4, 5]]
Hence all the magic.
Regarding [0] * (4 - len(times)) + times
you can read more here: Create List of Single Item Repeated n Times in Python
Long story short some_list * some_integer
creates a list that contains elements of some_list
repeated some_integer
times.