# Refer to examples in ReversibleDict.__str__
class PrintableList(list):
def __init__(self, list_, separator=', ', separate_last=False):
self.separator = separator
self.separate_last = separate_last
list.__init__(self, list_)
def __str__(self):
"""
Return a valid English string representation.
Example:
>>> for i in range(5): print(i, PrintableList(range(i)))
...
(0, [])
(1, [0])
(2, [0, 1])
(3, [0, 1, 2])
(4, [0, 1, 2, 3])
"""
separator = self.separator
separator_last = separator if self.separate_last else ' '
separator_last = '{0}and '.format(separator_last)
s = (str(i) for i in self)
s = separator.join(s)
s = separator_last.join(s.rsplit(separator, 1))
return s
class ReversibleDict(dict):
def reversed(self, sort_values=True):
"""
Return a reversed dict, with common values in the original dict
grouped into a list in the returned dict.
Example:
>>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
>>> d.reversed()
{1: ['d'], 2: ['b', 'c', 'f'], 3: ['a', 'e']}
"""
revdict = {}
for k, v in self.iteritems():
revdict.setdefault(v, []).append(k)
if sort_values:
revdict = dict((k, sorted(v)) for k, v in revdict.items())
return revdict
def _reversed_tuple_revlensorted(self):
"""
Return a tuple created from the reversed dict's items (see the
`reversed` method), with the items in the tuple being reverse sorted by
the length of the reversed dict's values.
Example:
>>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
>>> d._reversed_tuple_revlensorted()
((2, ['b', 'c', 'f']), (3, ['a', 'e']), (1, ['d']))
"""
revitems = self.reversed().items()
sortkey = lambda i: (len(i[1]), i[0])
revtuple = tuple(sorted(revitems, key=sortkey, reverse=True))
return revtuple
def __str__(self):
"""
Return a string representation of the reversed dict's items (see the
`reversed` method), sorted per the `_reversed_tuple_revlensorted`
method.
Example
>>> print(ReversibleDict({'a':3, 'c':2, 'b':2, 'e':3, 'd':1, 'f':2}))
b, c and f (2); a and e (3); and d (1)
>>> print(ReversibleDict({'a': 3, 'c': 2}))
a (3) and c (2)
"""
revtuple = self._reversed_tuple_revlensorted()
revstrs = ('{0} ({1})'.format(PrintableList(values), key)
for key, values in revtuple)
pl_args = ('; ', True) if (max(len(i[1]) for i in revtuple) > 1) else ()
revstrs = PrintableList(revstrs, *pl_args)
revstr = str(revstrs)
return revstr