DSU pattern (was Re: Trouble sorting lists (unicode/locale related?))
Alex Martelli
aleax at aleax.it
Mon Sep 22 10:46:15 EDT 2003
Duncan Booth wrote:
...
>>> So maybe it's about time to change the sort() method to support a
>>> second argument
>>>
>>> list.sort(compare=None, mapping=None)
>>>
>>> that, if provided, would perform the DSU magic. Or was that already
>>> proposed and rejected?
>>
>> I have not seen this proposed before, and I'm not very clear on what
>> the "compare" and "mapping" arguments are supposed to be in order to
>> let you specify any DSU. Basically it seems you would need two
>> callables, "decorate" to be called with each item in the list (to
>> return for each item the decorated tuple) and "undecorate" to be
>> called with each decorated tuple after the sort (to return the item
>> for the result). How do you turn that into "compare" and "mapping"?
>>
>>
> You don't need two callables because the sort function would be doing
> the decorating, so it knows also how to undecorate. I think the
> suggestion is that the mapping argument returns something that can be
> compared.
>
> For example, here is a DSU function that does a not-in-place sort and
> takes a suitable mapping argument. Changing it to in-place sort is,
> of course, trivial.
>
>>>> def DSU(aList, aMapping):
> newList = [ (aMapping(item), index, item) for (index, item)
Ah, I see -- the alleged "mapping" is in fact meant to be a
*CALLABLE*, NOT a mapping in the Python sense. Yes, you could
get away with just one callable in this way, of course. It
also seems to me that shoe-horning that second argument (in
practice mutually exclusive with the first one) to the sort
method, when there seem to be no real advantages to keeping
it a method, is not a great idea. Rather, a new built-in
function appears to me to be best here -- something like:
def sort(iterable, decorate=None):
if decorate is None:
aux = [ (item, index, item)
for index, item in enumerate(iterable) ]
else:
aux = [ (decorate(item), index, item)
for index, item in enumerate(iterable) ]
aux.sort()
return [ item for __, __, item in aux ]
so as to have no arbitrary constraints on the iterable being
a list, or the sort being necessarily in-place, when there
is no performance advantage in so doing -- and also serve the
frequent need of a non-in-place sort returning the sorted
list without any actual need for decoration. E.g., I often
use the equivalent of:
for key in sort(somesmalldict):
print key, somesmalldict[key]
and it would be handy to have that little 'sort' function
built-in for all such uses.
The only downside I can see to this proposal is that Python
isn't really all that good at passing the callable decorate
argument -- one would end up with a lot of little ad hoc
functions, or lambdas, and neither is a great solution. It's
the kind of situation where Smalltalk/Ruby shine by letting
an arbitrary block of code (albeit one only) be passed into
any method (in Ruby, this DSU-sort would probably become a
method of the Enumerable "module" [mix-in] -- a rather elegant
solution overall, "architecturally" nicer-looking than Python's,
although "pragmatically" we're probably abot even).
Alex
More information about the Python-list
mailing list