sort Python list with two keys but only one in reverse order

后端 未结 4 426
[愿得一人]
[愿得一人] 2020-11-28 13:40

I was wondering what would be a Pythonic way of sorting a list of tuples by two keys whereby sorting with one (and only one) key would be in a reverse order and sorting with

相关标签:
4条回答
  • 2020-11-28 13:47

    One way could be to create a reversor class and use it to decorate the key in question. This class could be used to reverse any field that is comparable.

    class reversor:
        def __init__(self, obj):
            self.obj = obj
    
        def __eq__(self, other):
            return other.obj == self.obj
    
        def __lt__(self, other):
            return other.obj < self.obj
    

    Use it like so:

    sortedList = sorted(myList, key=lambda(y): (y[0].lower(), reversor(y[1]))
    
    0 讨论(0)
  • 2020-11-28 13:49

    Two keys will be used when we need to sort a list with two constraints one in ascending order and other in descending in the same list or any
    In your example
    sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1])) can sort entire list only in one order
    you can try these and check whats happening

    sortedList = sorted(myList, key = lambda y: (y[0].lower(), -y[1]))
    sortedList = sorted(myList, key = lambda y: (-y[0].lower(), y[1]))
    sortedList = sorted(myList, key = lambda y: (-y[0].lower(), -y[1]))
    

    hope you will understand after this ;)

    0 讨论(0)
  • 2020-11-28 13:56

    Method 1

    A simple solution, but might not be the most efficient is to sort twice: the first time using the second element, the second using the first element:

    sortedList = sorted(sorted(myList, key=lambda (a,b):b, reverse=True), key=lambda(a,b):a)
    

    Or break down:

    tempList = sorted(myList, key=lambda (a,b):b, reverse=True)
    sortedList = sorted(tempList, key=lambda(a,b):a))
    

    Method 2

    If your elements are numbers, you can cheat a little:

    sorted(myList, key=lambda(a,b):(a,1.0/b))
    

    Method 3

    Another approach is to swap the elements when comparing the elements:

    def compare_func(x, y):
        tup1 = (x[0], y[1])
        tup2 = (x[1], y[0])
        if tup1 == tup2:
            return 0
        elif tup1 > tup2:
            return 1
        else:
            return -1
    
    sortedList = sorted(myList, cmp=compare_func)
    

    Or, using lambda to avoid writing function:

    sortedList = sorted(
        myList,
        cmd=lambda (a1, b1), (a2, b2): 0 if (a1, b2) == (a2, b1) else 1 if (a1, b2) > (a2, b1) else -1
        )
    

    I recommend against this approach as it is messy and the cmd keyword is not available in Python 3

    0 讨论(0)
  • 2020-11-28 14:09

    Sometimes there is little alternative but to use a comparator function. There was a cmp argument to sorted from its introduction to 2.4, but it was removed from Python 3 in favour of the more efficient key function. In 3.2, cmp_to_key was added to functools; it creates keys from the original objects by wrapping them in an object whose comparison function is based on the cmp function. (You can see a simple definition of cmp_to_key at the end of the Sorting How-To

    In your case, since lower-casing is relatively expensive, you might want to do a combination:

    class case_insensitive_and_2nd_reversed:
        def __init__(self, obj, *args):
            self.first = obj[0].lower()
            self.second = obj[1]
        def __lt__(self, other):
            return self.first < other.first or self.first == other.first and other.second < self.second
        def __lt__(self, other):
            return self.first < other.first or self.first == other.first and other.second < self.second
        def __gt__(self, other):
            return self.first > other.first or self.first == other.first and other.second > self.second
        def __le__(self, other):
            return self.first < other.first or self.first == other.first and other.second <= self.second
        def __ge__(self, other):
            return self.first > other.first or self.first == other.first and other.second >= self.second
        def __eq__(self, other):
            return self.first == other.first and self.second == other.second
        def __ne__(self, other):
            return self.first != other.first and self.second != other.second
    
    sortedList = sorted(myList, key = case_insensitive_and_2nd_reversed)
    
    0 讨论(0)
提交回复
热议问题