# Sorting a list to by another's order

Mark McEahern marklists at mceahern.com
Fri Aug 30 16:18:13 CEST 2002

```The code I just posted had a bug in it.  The problem is the whole "stick the
ones that aren't in there at the end."  Since sort takes a function that
just gives you x and y, the premise behind sort is you can look at two
elements, sort them, and apply that to the whole list and the whole list
will be sorted.  Stick the ones that aren't in there at the end breaks that
assumption, so you have to prep the list, moving those manually, before
using .sort().  This code does that and it also has unit tests to prove it.

#! /usr/bin/env python

"""

I need to sort listA so that its order corresponds to that of listB
(if the item in listA isn't in listB then it should be at the end of
the list).

"""

import unittest

def make_sort_by_list(list_with_order):
"""Return a function to sort a list using the order of
list_with_order."""
def sort_by_list(x, y):
try:
order_of_x = list_with_order.index(x)
order_of_y = list_with_order.index(y)
retval = cmp(order_of_x, order_of_y)
except ValueError:
retval = cmp(1, 0)
if __debug__:
print "sort(%s, %s) --> %d" % (x, y, retval)
return retval
return sort_by_list

def prep_list_for_sort(list_a, list_b):
"""Return a copy of list_a with all the items not in list_b at the
end."""
new_list = []
not_in_list = []
for x in list_a:
if x not in list_b:
not_in_list.append(x)
else:
new_list.append(x)
return new_list + not_in_list

class test(unittest.TestCase):

def test1(self):
list_a = ['d', 'c', 'f', 'a', 'b', 'e']
list_b = ['a', 'c', 'd', 'f']
list_a = prep_list_for_sort(list_a, list_b)
expected_order = ['a', 'c', 'd', 'f', 'b', 'e']
sort_by_b = make_sort_by_list(list_b)
list_a.sort(sort_by_b)
self.assertEquals(list_a, expected_order)

def test2(self):
list_a = ['a', 'c', 'd', 'f', 'b', 'e']
list_b = ['e', 'b', 'f']
list_a = prep_list_for_sort(list_a, list_b)
expected_order = ['e', 'b', 'f', 'a', 'c', 'd']
sort_by_b = make_sort_by_list(list_b)
list_a.sort(sort_by_b)
self.assertEquals(list_a, expected_order)

if __name__ == "__main__":
unittest.main()

-

```