【问题标题】:In python, how can we sort a list of tuples by specifying desc/asc for each element?在 python 中,我们如何通过为每个元素指定 desc/asc 来对元组列表进行排序?
【发布时间】:2020-02-27 07:04:28
【问题描述】:

在 SQL 中,我们可以为每个排序键指定 desc/asc 顺序,即order by key1 desc, key2 asc。 如何在 python 中对元组列表进行排序?

假设我有一个类似的列表

[("a", "b", "e"), ("b", "a", "c"), ("b", "a", "d")]

我想按 asc 顺序使用第二个键,按 desc 顺序使用第三个 ky。所以结果是

[("b", "a", "d"), ("b", "a", "c"), ("a", "b", "e")]

注意,元素可以是具有比较方法的任何类型(即__lt____gt__ 等)

【问题讨论】:

  • 你可以试试这个,sorted(sorted(l, key=lambda x:x[1]), key=lambda x:x[2], reverse=True)。可能有比这更好的解决方案!
  • 这可能会有所帮助。 stackoverflow.com/questions/3121979/…
  • @shaikmoeed 确实有比这更好的解决方案,即正确执行的解决方案:-P
  • @HeapOverflow 我觉得两次使用sort 是多余的。可能有比这更好的通用解决方案 ;-) !!!
  • @HeapOverflow 正如我之前所说,这个解决方案是多余的(因为当元组包含更多元素以按不同顺序排序时,它是不可扩展的)。是的,这可能是这个特定帖子的最佳选择,但我还没有测试过时间。

标签: python sorting


【解决方案1】:

你需要为排序构建一个合适的键函数 - 见Sort tuples based on second parameter 还有很多其他的

data = [("a", "b", "c"), ("b", "a", "c"), ("b", "a", "d")]


s = sorted(data, key = lambda x: (x[1],-ord(x[2]))) # "trick" to sort descending

print (s)

给予

[('b', 'a', 'd'), ('b', 'a', 'c'), ('a', 'b', 'c')]

您使用“自定义”元组作为键,需要有一点创意来构建它。

ord 函数为您提供字符的 ascii 值,通过否定它可以“降序”排序。

如果你排序的字母比字母多,你需要更有创意。


没有经过认真测试:

data = [("a", "b", "cesa"), ("b", "a", "ceta"), ("b", "a", "derived")]
s = sorted(data, key = lambda x: (x[1], tuple((-ord(t) for t in x[2])) ) )

得到

[('b', 'a', 'derived'), ('b', 'a', 'ceta'), ('a', 'b', 'cesa')]

【讨论】:

  • @patric-artner 谢谢你的回答。那么如果元素多于两个字母怎么办?在这种情况下我不能使用 ord 函数。
  • @shi 你仍然可以,但是你需要对所有字母都这样做 - 在这种情况下不需要调整 x[1] 因为它升序排序很好
  • 再次感谢。我更新了我的问题。事实上,我想问一个更一般的情况,而不仅仅是字符串或数字。我想调整任何可比较对象的排序顺序。
【解决方案2】:

您可以按优先级递减的顺序使用两种(它们是稳定的):

>>> from operator import itemgetter
>>> a = [("a", "b", "e"), ("b", "a", "c"), ("b", "a", "d")]

>>> a.sort(key=itemgetter(2), reverse=True)
>>> a.sort(key=itemgetter(1))

>>> a
[('b', 'a', 'd'), ('b', 'a', 'c'), ('a', 'b', 'e')]

上次我检查时,顺便说一下,这比具有更复杂键功能的单一排序更快。与创建新元组的关键函数相比,它占用的内存更少。

有关更多示例,请参阅 Python 的 Sorting HOW TO

【讨论】:

  • 非常感谢!这正是我想要的。
【解决方案3】:

我找到了一种创建具有自定义比较方法的排序器类的方法。这不是一种有效的方法,但效果很好。

from functools import total_ordering


def _apply(v, k):
    if callable(k):
        return k(v)
    else:
        return v[k]


def smart_sort(xs, getters_and_orders):
    orders = []
    getters = []
    for x in getters_and_orders:
        if isinstance(x, tuple):
            g, o = x
        else:
            g = x
            o = "desc"
        getters.append(g)
        orders.append(o)

    @total_ordering
    class _Sorter:
        def __init__(self, v):
            self._values = [_apply(v, g) for g in getters]

        def __eq__(self, other):
            return self._values == other._values

        def __lt__(self, other):
            for (a, b, o) in zip(self._values, other._values, orders):
                if a != b:
                    return a > b if o == "desc" else a < b
            return False

    return sorted(xs, key=_Sorter)


xs = [("a", "b", "e"), ("b", "a", "c"), ("b", "a", "d")]
ret = smart_sort(xs, [(1, "asc"), (2, "desc")])
print(ret)

>> [('b', 'a', 'd'), ('b', 'a', 'c'), ('a', 'b', 'e')]

【讨论】:

    猜你喜欢
    • 2010-10-06
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 2018-03-09
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    相关资源
    最近更新 更多