使用两个键排序Python列表,但只有一个按相反顺序排序

时间:2016-06-08 04:37:23

标签: python sorting

我想知道用两个键对元组列表进行排序的Pythonic方法是什么,其中用一个(并且只有一个)键进行排序将是相反的顺序,而用另一个键进行排序将不区分大小写。 更具体地说,我有一个包含元组的列表:

myList = [(ele1A, ele2A),(ele1B, ele2B),(ele1C, ele2C)]

我可以使用以下代码用两个键对其进行排序:

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

要按相反顺序排序,我可以使用

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

但是这将使用两个键以相反的顺序排序。

任何提示都非常赞赏。

5 个答案:

答案 0 :(得分:10)

当我们需要使用两个约束对列表进行排序时,将使用两个键,一个按升序排序,另一个按降序排列在同一列表中或任何列表中
在您的示例中,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]))
sortedList = sorted(myList, key = lambda y: (-y[0].lower(), -y[1]))

希望你能在此之后理解;)

答案 1 :(得分:1)

有时除了使用比较器功能之外别无选择。从{4}引入到cmp有一个sorted参数,但它已从Python 3中删除,转而使用效率更高的key函数。在3.2中,cmp_to_key被添加到functools;它通过将它们包装在比较函数基于cmp函数的对象中来创建原始对象的键。 (您可以在the perl special variable, $.

看到cmp_to_key的简单定义

在您的情况下,由于较低的套管相对较贵,您可能需要进行组合:

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)

答案 2 :(得分:0)

一种方法可能是创建一个反向器类,并使用它来装饰有问题的键。该类可用于反转任何可比较的字段。

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

像这样使用它:

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

答案 3 :(得分:0)

也许是优雅但效率不高的方式:

reverse_key = functools.cmp_to_key(lambda a, b: (a < b) - (a > b))
sortedList = sorted(myList, key = lambda y: (reverse_key(y[0].lower()), y[1]))

答案 4 :(得分:-1)

方法1

一个简单的解决方案,但可能不是最有效的是排序两次:第一次使用第二个元素,第二个使用第一个元素:

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

或分解:

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

方法2

如果你的元素是数字,你可以作弊:

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

方法3

另一种方法是在比较元素时交换元素:

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)

或者,使用lambda来避免编写函数:

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

我建议不要使用这种方法,因为它很麻烦且Python 3中没有cmd关键字