| |
comp.lang.python |
> I know, it's somewhat silly, but I went through a little tutorial I would like to add yet another way of sorting: a little Let's take the Spam class: Or you can sort on Spam.eggs, Spam.spam: But what if you want to sort inverse on spam? Define a CompInverse: OK, and now sort on eggs and inverse on spam: We can use our little framework to sort tables as well: >>> table=[(1,2), (1,3), (1,0), (2,0), (0,3), (3,2)] In terms of design patterns, we can identify CmpInverse [1] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Michael
> here showing a half dozen ways to sort a list with the built-in
> "sort" method. It was short so I wrote it up in case it is
> deserving of a mini HOWTO. (Yeah, I still haven't written up the
> exception classes HOWTO ): I think it's deserving because there's
> not one spot in the manual or Lutz' book talking about the different
> ways.
[snip]
> >>> class CmpAttr:
> >>> def __init__(self, attr):
> >>> self.attr = attr
> >>> def __call__(self, x, y):
> >>> return cmp(getattr(x, self.attr), getattr(y, self.attr))
sorting framework using design patterns [1]. A few days
ago, a colleague asked me how to sort tables on different
columns (some of them might be sorted inverse). In a
few minutes I created a little framework in python
(which he then implemented in C++). This is yet another
example of python as prototyping language. But I think,
the framework can also be used in python directly.
>>> def __init__(self, spam, eggs):
>>> self.spam = spam
>>> self.eggs = eggs
>>> def __repr__(self):
>>> return 'Spam(s=%s,e=%s)' %(repr(self.spam),repr(self.eggs))
>>> a = [Spam(1, 4), Spam(9, 3), Spam(4,6),Spam(4,4)]
two attributes) you might use the composite comparer:
>>> """Takes a list of compare functions and sorts in that order."""
>>> def __init__(self,*comparers):
>>> self.comparers=comparers
>>> def __call__(self,a,b):
>>> for cmp in self.comparers:
>>> c=cmp(a,b)
>>> if c:
>>> return c
>>> return 0
>>> print a
>>> print a
>>> """Inverses the effect of a cmp."""
>>> def __init__(self,cmp):
>>> self.cmp=cmp
>>> def __call__(self,a,b):
>>> return -self.cmp(a,b)
>>> """Sorts on an index of a sequence."""
>>> def __init__(self,column):
>>> self.column=column
>>> def __call__(self,a,b):
>>> return cmp(a[self.column],b[self.column])
>>> print table
as a Decorator and CmpComposite as Composite pattern.
CmpColumn and CmpAttr are Strategy patterns. It is now
relatively easy to sort on arbitrary combinations of
attributes. The disadvantage is: it can become quite
slow for big lists.
Design Patterns: Elements of Reusable Object-Oriented Software.
Addison-Wesley Pub Co; ISBN: 0201633612; 1994.
http://www.amazon.com/exec/obidos/ASIN/0201633612
--
''''\ Michael Scharf
` c-@@ TakeFive Software
` > http://www.TakeFive.com
\_ V mailto:Michael_Sch...@TakeFive.co.at
[
class CmpComposite: class CmpInverse: class CmpColumn: def test(): l=[3,5,6,71,2,3,4,5] table=[ print 'sort l[0], inv l[1]' print 'sort inv l[1], l[0]' class Spam: print "sort spam:" print "sort inv spam:" print "sort spam, eggs:" print "sort eggs, spam:" print "sort eggs, inv spam:" if __name__=='__main__':
Comparers.py 2K ]
"""A set of comparer classes."""
"""Takes a list of compare functions and sorts in that order."""
def __init__(self,*comparers):
self.comparers=comparers
def __call__(self,a,b):
for cmp in self.comparers:
c=cmp(a,b)
if c:
return c
return 0
"""Inverses the effect of a cmp."""
def __init__(self,cmp):
self.cmp=cmp
def __call__(self,a,b):
return -self.cmp(a,b)
"""Sorts on an index of a sequence."""
def __init__(self,column):
self.column=column
def __call__(self,a,b):
return cmp(a[self.column],b[self.column])
class CmpAttr:
"""Sorts on an attribute."""
def __init__(self, attr):
self.attr = attr
def __call__(self, x, y):
return cmp(getattr(x, self.attr), getattr(y, self.attr))
print 'sort inv'
s=CmpInverse(cmp)
l.sort(s)
print ' ',l
(1,2),
(1,3),
(1,0),
(2,0),
(0,3),
(3,2)
]
table.sort(CmpComposite(CmpColumn(0),CmpInverse(CmpColumn(1))))
print ' ',table
table.sort(CmpComposite(CmpInverse(CmpColumn(1)),CmpColumn(0)))
print ' ',table
def __init__(self, spam, eggs):
self.spam = spam
self.eggs = eggs
def __repr__(self):
return 'Spam(s=%s,e=%s)' %(repr(self.spam),repr(self.eggs))
a = [Spam(1, 4), Spam(9, 3), Spam(4,6),Spam(4,4)]
a.sort(CmpAttr('spam'))
print ' ',a
a.sort(CmpInverse(CmpAttr('spam')))
print ' ', a
a.sort(CmpComposite(CmpAttr('spam'),CmpAttr('eggs')))
print ' ',a
a.sort(CmpComposite(CmpAttr('eggs'),CmpAttr('spam')))
print ' ',a
a.sort(CmpComposite(CmpAttr('eggs'),CmpInverse(CmpAttr('spam'))))
print ' ',a
test()