Sorting a list depending of the indexes of another sorted list

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Mon Jan 21 08:58:48 EST 2008


On Mon, 21 Jan 2008 09:53:10 +0100, Peter Otten wrote:

> Santiago  Romero wrote:
> 
>>  I'm trying to sort both lists so that they end like this:
>> 
>> preferences = [10, 20, 30]
>> hosts = [ "mx1.domain.com", "mx2.domain.com", "anotherhost.domain.com"
>> ]
>> 
>>  I want to sort hosts list depending on the numeric order of
>> "preferences".
> 
> The following relies on undocumented (I hope) behaviour:


What bit are you suggesting is undocumented?


>>>> preferences = [10, 30, 20]
>>>> hosts = [ "mx1.domain.com", "anotherhost.domain.com", 
>... "mx2.domain.com"] 
>>>> hosts.sort(key=lambda x, p=iter(preferences).next: p())
>>>> preferences.sort()
>>>> hosts
> ['mx1.domain.com', 'mx2.domain.com', 'anotherhost.domain.com']
>>>> preferences
> [10, 20, 30]

Now if you wanted to claim it was opaque and confusing, I'd agree with 
you :-)


Here's a function that uses the Decorate-Sort-Undecorate technique to 
sort one list by the contents of another:



from sys import maxint
_indices = xrange(maxint)

def sorterDSU(alist, blist):
    """Return a copy of alist sorted by the contents of blist."""
    assert len(alist) == len(blist)
    decorated = zip(blist, _indices, alist)
    decorated.sort()
    return [avalue for (bvalue, i, avalue) in decorated]



Here's another version:

def sorter(alist, blist):
    assert len(alist) == len(blist)
    table = sorted(range(len(alist)), key=blist.__getitem__)
    return [alist[i] for i in table]



>>> alist = "John Eric Michael Graham Terry-J Terry-G".split()
>>> blist = [5, 0, 4, 1, 3, 2]
>>> sorter(alist, blist)
['Eric', 'Graham', 'Terry-G', 'Terry-J', 'Michael', 'John']



-- 
Steven



More information about the Python-list mailing list