bidict/docs/sortedbidicts.rst.inc

96 lines
3.5 KiB
PHP

.. _sortedbidicts:
Sorted Bidict Recipes
#####################
Suppose you need a bidict that maintains its items in sorted order.
The Python standard library does not include any sorted dict types,
but the excellent
`sortedcontainers <http://www.grantjenks.com/docs/sortedcontainers/>`_ and
`sortedcollections <http://www.grantjenks.com/docs/sortedcollections/>`_
libraries do.
Armed with these along with bidict's
:attr:`fwd_cls <bidict.BidictBase.fwd_cls>`
and
:attr:`inv_cls <bidict.BidictBase.inv_cls>`
attributes,
creating a sorted bidict type is dead simple::
>>> import bidict, sortedcontainers
>>> # a sorted bidict whose forward items stay sorted by their keys,
>>> # and whose inverse items stay sorted by *their* keys (i.e. it and
>>> # its inverse iterate over their items in different orders):
>>> class SortedBidict1(bidict.bidict):
... fwd_cls = sortedcontainers.SortedDict
... inv_cls = sortedcontainers.SortedDict
... __reversed__ = lambda self: reversed(self.fwdm)
>>> b = SortedBidict1({'Tokyo': 'Japan', 'Cairo': 'Egypt'})
>>> b
SortedBidict1([('Cairo', 'Egypt'), ('Tokyo', 'Japan')])
>>> b['Lima'] = 'Peru'
>>> # b stays sorted by its keys:
>>> list(b.items())
[('Cairo', 'Egypt'), ('Lima', 'Peru'), ('Tokyo', 'Japan')]
>>> # b.inv stays sorted by *its* keys (b's values!)
>>> list(b.inv.items())
[('Egypt', 'Cairo'), ('Japan', 'Tokyo'), ('Peru', 'Lima')]
>>> # a sorted bidict whose forward items stay sorted by their keys,
>>> # and whose inverse items stay sorted by their values (i.e. it and
>>> # its inverse iterate over their items in the same order):
>>> import sortedcollections
>>> class SortedBidict2(bidict.bidict):
... fwd_cls = sortedcontainers.SortedDict
... inv_cls = sortedcollections.ValueSortedDict
... __reversed__ = lambda self: reversed(self.fwdm)
>>> element_by_atomic_number = SortedBidict2({
... 3: 'lithium', 1: 'hydrogen', 2: 'helium'})
>>> # stays sorted by key:
>>> element_by_atomic_number
SortedBidict2([(1, 'hydrogen'), (2, 'helium'), (3, 'lithium')])
>>> # .inv stays sorted by value:
>>> list(element_by_atomic_number.inv.items())
[('hydrogen', 1), ('helium', 2), ('lithium', 3)]
>>> element_by_atomic_number[4] = 'beryllium'
>>> list(element_by_atomic_number.inv.items())
[('hydrogen', 1), ('helium', 2), ('lithium', 3), ('beryllium', 4)]
>>> # order is preserved correctly when passing .inv back into constructor:
>>> atomic_number_by_element = SortedBidict2(element_by_atomic_number.inv)
>>> list(atomic_number_by_element.items()) == list(element_by_atomic_number.inv.items())
True
>>> # copies of .inv preserve order correctly too:
>>> list(element_by_atomic_number.inv.copy().items()) == list(atomic_number_by_element.items())
True
>>> # To pass method calls through to the _fwd SortedDict when not present
>>> # on the bidict instance, provide a custom __getattribute__ method:
>>> def __getattribute__(self, name):
... try:
... return object.__getattribute__(self, name)
... except AttributeError as e:
... try:
... return getattr(self.fwdm, name)
... except AttributeError:
... raise e
>>> SortedBidict2.__getattribute__ = __getattribute__
>>> # bidict has no .peekitem attr, so the call is passed through to _fwd:
>>> element_by_atomic_number.peekitem()
(4, 'beryllium')