469,572 Members | 1,202 Online

# Combined natural and unnatural list sorting

Hello All,

I need to sort a list using an unnatural sequence.

I have a list like so:

foo = ["White/M", "White/L", "White/XL", "White/S", "Black/S", "Black/M"]

print foo.sort()

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

["White/S","White/M", "White/L", "White/XL", "Black/S", "Black/M"]
So, in other words, I need the colors sorted alphabetically and the the sizes
sorted logically.

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?

Thanks a million,
Derek

__________________________________
Do you Yahoo!?
Yahoo! Mail - You care about security. So do we.
http://promotions.yahoo.com/new_mail

Jul 18 '05 #1
3 1603
* Derek Basch (2004-06-15 23:38 +0100)
Hello All,

I need to sort a list using an unnatural sequence.

I have a list like so:

foo = ["White/M", "White/L", "White/XL", "White/S", "Black/S", "Black/M"]

print foo.sort()

['White/L', 'White/M', 'White/S', 'White/XL', 'Black/M', 'Black/S']

The order that I actually need is:

["White/S","White/M", "White/L", "White/XL", "Black/S", "Black/M"]

So, in other words, I need the colors sorted alphabetically and the the sizes
sorted logically.

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?

You need some kind of general "function sort" (either using the
"Decorate, Sort, Undecorate" or the "pass a function" idiom):

def funcsort(seq, function, modus = 'dsu'):
"""
sort seq by function(item)
"""

if modus == 'dsu':
seq = [(function(item), index, item) for index, item in enumerate(seq)]
seq.sort()
return [item[2] for item in seq]
elif modus == 'pass':
seq = seq[:]
seq.sort(lambda x, y: cmp(function(x), function(y)))
return seq

This is a common kind of sort problem so you will need this "function
sort" anyway in near future.

Then your problem simply translates to find a function that generates
your sort items like you want them sorted (in this case something like
'White/M' -> ('White', 2) ):

SIZE_MAP = {'S': 1,
'M': 2,
'L': 3,
'XL': 4}

def func(item):
splititem = item.split('/')
return splititem[0], SIZE_MAP[splititem[1]]

print funcsort(foo, func)
Thorsten
Jul 18 '05 #2
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

Jul 18 '05 #3
In article <ca*************@news.t-online.com>, __*******@web.de says...
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

Wow! Thanks for sharing the knowledge everyone. I think I am starting to
get my head around these sorting idioms. It will take me a bit to study
all the code you sent. Every day the forums remind me what a noob I am
;)
Jul 18 '05 #4

### This discussion thread is closed

Replies have been disabled for this discussion.