Python Sorted() 函数多关键字排序

3

我在HackerRank网站上遇到了一个问题,我用自己的逻辑解决了它,但有人有一个更好的解决方案,我很难理解。

Question: Your task is to sort the string in the following manner: All sorted lowercase letters are ahead of uppercase letters. All sorted uppercase letters are ahead of digits. All sorted odd digits are ahead of sorted even digits.

Answer:

print(*sorted(input(), key=lambda c: (c.isdigit() - c.islower(), c in '02468', c)), sep='')

请问有人能解释一下上面的lambda函数吗?更具体地说,c.isdigit() - c.islower()是在做什么?


我会这样表达:isdigit检查c是否为数字,isdigit-islower用于“所有排序的小写字母都在数字之前(有效地)”。 - kesarling He-Him
3
布尔值是int的子类。如果你将True视为1,将False视为0,那么这句话应该更容易理解。 - Klaus D.
3个回答

2

如果我尝试减去两个布尔值,它会给我一个整数,因为布尔值是 int 的子类:

>>> True - True
0
>>> False - False
0
>>> False - True
-1

在您的情况下,第一个布尔值对应于 c.isdigit() 的结果,第二个布尔值对应于 c.islower() 的结果。
所以:
>>> True - True  # ex: '7' -> isdigit(): True, islower(): True -> 1 - 1 = 0
0
>>> False - False  # ex: 'B' -> isdigit(): False, islower(): False -> 0 - 0 = 0
0
>>> False - True  # ex: 'g' -> isdigit(): False, islower(): True -> 0 - 1 = -1
-1

元组中的每个项目将用于检查顺序。从第一个项目开始,如果存在平局,则继续到第二个和第三个项目。

了解布尔值可以相互比较((True > False) is True)并且字符串也可以进行比较('abc' < 'xyz'),您可以按照以下元组顺序排序:

(-1, 0, 'g') < (0, 0, 'B') < (0, 0, '7') < (0, 1, '6') < (0, 1, '8')

由于sorted默认按升序排序,因此您得到了您所期望的结果:小写字母排在大写字母之前,奇数数字排在偶数数字之前。


2
这是关于 sorted() 内置函数的简介,它可以从可迭代对象中构建一个新的排序列表。
sorted() 函数具有 key 参数,用于指定在进行比较之前对每个列表元素调用的函数。 key 参数的值应该是一个函数,它接受一个参数并返回一个用于排序目的的键(在这种特殊情况下是元组)。这种技术很快,因为 key 函数对每个输入记录仅被调用一次。
让我们将 sorted 函数拆分成更易读的代码块。
def key_function(character):
    print((character.isdigit() - character.islower(), character in "02468", character))
    return (character.isdigit() - character.islower(), character in "02468", character)


input_string = "1949 Film Prejudice"

print(*sorted(input_string, key=key_function), sep="")

这是我为了解释问题而构造的元组中间列表。

[
    (1, False, "1"),
    (1, False, "9"),
    (1, True, "4"),
    (1, False, "9"),
    (0, False, " "),
    (0, False, "F"),
    (-1, False, "i"),
    (-1, False, "l"),
    (-1, False, "m"),
    (0, False, " "),
    (0, False, "P"),
    (-1, False, "r"),
    (-1, False, "e"),
    (-1, False, "j"),
    (-1, False, "u"),
    (-1, False, "d"),
    (-1, False, "i"),
    (-1, False, "c"),
    (-1, False, "e"),
]

这些元组之间的比较是理解其工作原理的关键。
如果您只是对这个使用元组比较进行排序的列表进行排序,您将得到所需的结果。
我们将介绍在(1, False, "1") > (1, False, "9")期间发生的3个比较方面:
  1. 整数比较
  2. 布尔比较
  3. 字符比较

整数比较

整数比较直观,因为我们只需要处理整数。

布尔比较

只是为了展示True曾经是False的内容

PEP 285

(True和False常量在Python 2.2.1中添加到内置函数中,但2.2.1版本仅设置为1和0的整数值,并且不是不同的类型。)

所以它们之间的比较也与整数之间的比较相同。
True - False 的结果是 1False - True 的结果是 -1

字符比较

这些字符串按照它们的字符的 ASCII 值排序(p 在 ASCII 中是 112,而 P 是 80)。 从技术上讲,Python 比较这些字符的 Unicode 代码点(也就是 ord 所做的),ASCII 字符的 Unicode 代码点恰好等于其 ASCII 值。

所以最终也归结为整数比较。
希望现在您已经对那个 sorted 函数中发生的事情有了很好的理解 :)

https://treyhunner.com/2019/03/python-deep-comparisons-and-code-readability/


1
重点在于元组,Python将根据键的第一个元素确定元素的排序位置,以满足唯一位置即不等比较。在这种情况下,元组键为每个值分配不同的键。
例如:c = '1234ABab',现在对于第0个元素'1',isdigit()将返回True被转换为1,islower()为0,因此键的第一个元素将是1,第二个将是0,第三个将是'1'本身。因此,该元素的键是(1,0,'1'),奇数的情况都是如此。对于偶数,键将是(1,1,'2'),对于小写字母,键将是(-1,0,'a'),对于大写字母,键将是(0,0,'A')。这样,按顺序完成排序,满足键元素。
更多内容,请搜索排序中的元组键。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接