outline-style sorting algorithm

Delaney, Timothy C (Timothy) tdelaney at avaya.com
Wed Apr 28 20:52:48 EDT 2004


Thorsten Kampe wrote:

>>>>> foo
>> ['1.0', '1.0.1', '1.1.1', '1.2', '1.9', '1.10', '1.11', '1.20',
>> '1.20.1', '1.30']
>>>>> foo.sort()
>>>>> foo
>> ['1.0', '1.0.1', '1.1.1', '1.10', '1.11', '1.2', '1.20', '1.20.1',
>> '1.30', '1.9'] 
>> 
>> Obviously 1.20.1 should be after 1.9 if we look at this as
>> dot-delimited integers, not as decimal numbers.
> 
> You need some general approach to avoid the DSU thing:
> 
> def funcsort(seq, func):
>     """ sort seq by func(item) """
>     seq = seq[:]
>     seq.sort(lambda x, y: cmp(func(x), func(y)))
>     return seq
> 
> funcsort(foo, lambda x: map(int, x.split('.')))

I've seen you give this advice several times, today, and IMO it's
completely wrong.

DSU is *exactly* what you want to do. If you want to wrap it inside a
general function, that's fine, but DSU is in almost all cases preferred
to passing a comparison function - it's much faster.

    def sorted (seq, cmp=None, key=None):
        """ sort seq by func(item) """
        if key is None:
            seq = seq[:]
        else:
            seq = [(key(e), i, e) for i, e in enumerate(seq)]

        seq.sort(cmp)

        if key is None:
            return seq
        else:
            return [i[-1] for i in seq]

    foo = ['1.0', '1.0.1', '1.1.1', '1.2', '1.9', '1.10', '1.11',
'1.20', '1.20.1', '1.30']

    foo = sorted(foo, key=lambda x: map(int, x.split('.')))
    print foo

Note that Python 2.4 will have DSU as a built-in idiom to `list.sort`
i.e. `list.sort(key=func)` but will be somewhat more efficient than the
above. Likewise there will be a new builtin `sorted` which has exactly
the same semantics as the above - it is stable, and it does not ever
compare the actual value if a key function is supplied - only the key
value (the above also compares the position, but that's an
implementation detail and has no visible effect).

Tim Delaney




More information about the Python-list mailing list