在 Python 3.x 中找到 Python 2.7 排序行为的类似物

Find an analogue for the Python 2.7 sorting behavior in Python 3.x

在 Python 2.7 中,可以将 sorted 函数与包含不同类型的列表一起使用,例如字符串、元组、整数,像这样:

some_list = ['a', 'b', 1, ('c', 'd'), [2, 3, 4]]

>>> sorted(some_list)

[1, [2, 3, 4], 'a', 'b', ('c', 'd')]

然而,如果我们尝试在 Python 3 中做这样的事情,我们将得到一个异常:

some_list = ['a', 'b', 1, ('c', 'd'), [2, 3, 4]]

>>> sorted(some_list)

TypeError: '<' not supported between instances of 'int' and 'str'

从 python2.7 模仿 sorted 函数行为的最简单方法是什么?我知道我可以为此目的编写自己的方法,但也许在某些库中实现了类似的功能或移动到另一个特定的内置函数?

您应该能够通过适当的 key 功能获得您想要的东西。例如:

>>> some_list = ['a', 'b', 1, ('c', 'd'), [2, 3, 4]]
>>> sorted(some_list, key=lambda i: str(i[0] if hasattr(i, "__getitem__") else i))
[1, [2, 3, 4], 'a', 'b', ('c', 'd')]

key 的详细信息将完全取决于您希望如何处理不同类型的项目之间的比较——上面的示例假定您希望使用 string-based 比较,但可能有其他方法。

您需要为 sortsorted 提供一个明确的 key,并且键应该解释如何比较不同类型的元素。

一个快速的解决方案是将元素 x 替换为元组 (type(x).__name__, x) 以便元素首先按类型分组,并且仅在它们具有相同类型时才进行比较:

some_list = ['a', [4, 5, 6], 3, 2.0, 'b', 1, 1.5, ('c', 'd'), [2, 3, 4]]

some_list.sort(key=lambda x: (type(x).__name__, x))

print(some_list)
# [1.5, 2.0, 1, 3, [2, 3, 4], [4, 5, 6], 'a', 'b', ('c', 'd')]

注意整数是如何与浮点数分开的。如果你不想要那个,你需要一个更复杂的密钥。我在这个 post.

的底部举了一个例子

您可以尝试其他键,这将导致不同的顺序:

  • key=strkey=repr:在比较之前将所有内容粗暴地转换为字符串。这有一个缺点,即数字按字典顺序进行比较,因此 1 < 10 < 2.
  • key=lambda x: tuple(more_itertools.collapse(x)) 这会将所有内容扁平化为元组,因此单个数字相当于一个数字的列表,列表列表的列表相当于一个简单的列表。但是如果尝试将数字与字符串进行比较,它仍然会崩溃。
  • 上述两种解决方案的一些混合方法。您可以像任何函数一样声明一个复杂的键,使用 def 关键字。
  • 尝试将元素与它们通常的比较进行比较,如果引发异常,则将元素转换为字符串并再次比较:
from functools import cmp_to_key

def cmp(a,b):
    try:
        return (a > b) - (a < b)
    except TypeError:
        a, b = str(a), str(b)
        return (a > b) - (a < b)

k = cmp_to_key(cmp)

some_list = ['a', [4, 5, 6], 3, 2.0, 'b', 1, 1.5, ('c', 'd'), [2, 3, 4]]

some_list.sort(key=k)

print(some_list)
# [('c', 'd'), 1, 1.5, 2.0, 3, [2, 3, 4], [4, 5, 6], 'a', 'b']