Search code examples
pythonsortingtuplescustom-function

Sorting tuples with a custom sorting function using a range?


I would like to sort a list of tuples based on the two last columns:

mylist = [(33, 36, 84), 
          (34, 37, 656), 
          (23, 38, 42)]

I know I can do this like:

final = sorted(mylist, key:lambda x: [ x[1], x[2]])

Now my problem is that I want to compare the second column of my list with a special condition: if the difference between two numbers is less than an offset they should be taken as equal ( 36 == 37 == 38) and the third column should be used to sort the list. The end result I wish to see is:

mylist = [(23, 38, 42)
          (33, 36, 84), 
          (34, 37, 656)]

I was thinking of creating my own integer type and overriding the equal operator. Is this possible? is it overkill? Is there a better way to solve this problem?


Solution

  • I think the easiest way is to create a new class that compares like you want it to:

    mylist = [(33, 36, 84), 
              (34, 37, 656), 
              (23, 38, 42)]
    
    offset = 2
    
    class Comp(object):
        def __init__(self, tup):
            self.tup = tup
    
        def __lt__(self, other):  # sorted works even if only __lt__ is implemented.
            # If the difference is less or equal the offset of the second item compare the third
            if abs(self.tup[1] - other.tup[1]) <= offset:
                return self.tup[2] < other.tup[2]
            # otherwise compare them as usual
            else:
                return (self.tup[1], self.tup[2]) < (other.tup[1], other.tup[2])
    

    A sample run shows your expected result:

    >>> sorted(mylist, key=Comp)
    [(23, 38, 42), (33, 36, 84), (34, 37, 656)]
    

    I think it's a bit cleaner than using functools.cmp_to_key but that's a matter of personal preference.