icalendar uses its own CaselessDict as the base of many classes. I needed to produce the keys and items in a canonical order, so that certain keys would appear first.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | class CaselessDict(dict):
"""
A dictionary that isn't case sensitive, and only uses strings as keys.
Values retain their case.
"""
# Implementation Omitted
# A list of keys that must appear first in sorted_keys and sorted_items;
# must be uppercase.
canonical_order = None
def sorted_keys(self):
"""
Sorts keys according to the canonical_order for the derived class.
"""
return canonsort_keys(self.keys(), self.canonical_order)
def sorted_items(self):
"""
Sorts items according to the canonical_order for the derived class.
"""
return canonsort_items(self, self.canonical_order)
def canonsort_keys(keys, canonical_order=None):
"""
Sorts leading keys according to canonical_order.
Keys not specified in canonical_order will appear alphabetically at the end.
>>> keys = ['DTEND', 'DTSTAMP', 'DTSTART', 'UID', 'SUMMARY', 'LOCATION']
>>> canonsort_keys(keys)
['DTEND', 'DTSTAMP', 'DTSTART', 'LOCATION', 'SUMMARY', 'UID']
>>> canonsort_keys(keys, ('SUMMARY', 'DTSTART', 'DTEND', ))
['SUMMARY', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'UID']
>>> canonsort_keys(keys, ('UID', 'DTSTART', 'DTEND', ))
['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY']
>>> canonsort_keys(keys, ('UID', 'DTSTART', 'DTEND', 'RRULE', 'EXDATE'))
['UID', 'DTSTART', 'DTEND', 'DTSTAMP', 'LOCATION', 'SUMMARY']
"""
canonical_map = dict((k, i) for i, k in enumerate(canonical_order or []))
head = [k for k in keys if k in canonical_map]
tail = [k for k in keys if k not in canonical_map]
return sorted(head, key=lambda k: canonical_map[k]) + sorted(tail)
def canonsort_items(dict1, canonical_order=None):
"""
Returns a list of items from dict1, sorted by canonical_order.
>>> d = dict(i=7, c='at', a=3.5, l=(2,3), e=[4,5], n=13, d={'x': 'y'}, r=1.0)
>>> canonsort_items(d)
[('a', 3.5), ('c', 'at'), ('d', {'x': 'y'}), ('e', [4, 5]), ('i', 7), ('l', (2, 3)), ('n', 13), ('r', 1.0)]
>>> canonsort_items(d, ('i', 'c', 'a'))
[('i', 7), ('c', 'at'), ('a', 3.5), ('d', {'x': 'y'}), ('e', [4, 5]), ('l', (2, 3)), ('n', 13), ('r', 1.0)]
"""
return [(k, dict1[k]) for k in canonsort_keys(dict1.keys(), canonical_order)]
|
canonsort_keys
computes a dictionary mapping the strings in canonical_order
to their index. This canonical_map
is used three different ways:
- to compute
head
, an unordered list comprehension of thosekeys
present incanonical_order
; - to compute
tail
, allkeys
not present incanonical_order
; - in the
key
function used to sorthead
. (tail
is sorted lexicographically.)
Tags: dictionary, sorting