Combined natural and unnatural list sorting

Peter Otten __peter__ at web.de
Thu Jun 17 00:33:42 CEST 2004


Derek Basch wrote:

> I have a list like so:
> 
> foo = ["White/M", "White/L", "White/XL", "White/S", "Black/S", "Black/M"]

> The order that I actually need is:
> 
> ["White/S","White/M", "White/L", "White/XL", "Black/S", "Black/M"]

> I looked for a while at using comparison functions with sort but I don't
> think that will work. Anyone been down this road? Suggestions?

Here's a slightly more complicated approach. Turn what was the "unnatural"
into the "natural" order:

from itertools import count

class Size(object):
    all = {}
    _nextIndex = count().next

    def __new__(cls, name):
        try:
            return cls.all[name]
        except KeyError:
                self = object.__new__(cls, name)
                self.name = name
                self.index = cls._nextIndex()
                cls.all[name] = self
                return self

    def __init__(self, name):
        pass

    def __lt__(self, other):
        return self.index < other.index

    def __str__(self):
        return self.name

for size in "XXS XS S M L XL XXL".split():
    Size(size)
del size

class TShirt(object):
    def __init__(self, colorSize):
        self.color, size = colorSize.split("/")
        self.size = Size(size)

    def __lt__(self, other):
        if self.color == other.color:
            return self.size < other.size
        return self.color < other.color

    def __str__(self):
        return "%s/%s" % (self.color, self.size)

stock = map(TShirt, ["White/M", "White/L", "White/XL", "White/S", "Black/S",
"Black/M"])

# color, size
stock.sort()
for tshirt in stock:
    print tshirt
print "---"

# size, color
stock.sort(lambda s, t: cmp(s.size, t.size) or cmp(s.color, t.color))
for tshirt in stock:
    print tshirt

Peter




More information about the Python-list mailing list