sort(): Giving third argument?
Alex Martelli
aleax at aleax.it
Fri Mar 21 06:06:05 EST 2003
Thomas Guettler wrote:
> Hi!
>
> If I have a list of IDs and a hash which maps
> each ID to a name:
>
> ids=[1, 2, 3, 4]
>
> names={
> 1: "foo",
> 2: "bar",
> ...}
>
> I can't do the following:
>
> def mycmp(a, b):
> return cmp(names[a], names[b])
>
> ids.sort(mycmp)
>
> since "name" is unkown in mycmp.
>
> What's the best solution?
decorate-sort-undecorate, as is almost invariably
the case for sorting.
decorated = [ (names[i], i) for i in ids ]
decorated.sort()
ids[:] = [ i for name, i in decorated ]
the assignment to ids[:] in the undecorate step is
only needed if you do want the sort to be in-place.
DSU is most often faster and simpler than passing
a comparison callable to the sort method.
If you ARE keen on passing a comparison callable
come hell or high water, you can do that in several
ways, as is always the case when you want a callable
built to keep some state. Simplest is generally a
closure:
def make_comparer(names):
def comparer(a, b, names=names):
return cmp(names[a], names[b])
return comparer
and ids.sort(make_comparer(names))
the "names=names" trick is only _needed_ in very
old versions of Python, by the way.
Only slightly more complicated than a closure is
a class whose instances are callable:
class Comparer:
def __init__(self, names):
self.names = names
def __call__(self, a, b):
return cmp(self.names[a], self.names[b])
and ids.sort(Comparer(names))
But -- DO consider DSU: it's really a superior approach!
Alex
More information about the Python-list
mailing list