这是一个字符串排序,排序规则:小写<大写<奇数<偶数
s = 'asdf234GDSdsf23' #排序:小写-大写-奇数-偶数
print("".join(sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))))
这里key接受的函数返回的是一个元组?是如何进行比较的?
PHP中文网2017-04-17 17:49:14
让我们从一个简单的例子开始:
items = [(1, 2), (2, 1)]
print(sorted(items))
结果:
[(1, 2), (2, 1)]
items
是一个list of tuple,如果针对tuple 排序,Python 的Builtin function sorted
(或是sort
) 会从tuple 的最后一个元素开始进行排序,也就是说一组二元素的tuple 进行排序可以想像成两次基本的排序:items
是一個 list of tuple,如果針對 tuple 排序,Python 的 Builtin function sorted
(或是sort
) 會從 tuple 的最後一個元素開始進行排序,也就是說一組二元素的 tuple 進行排序可以想像成兩次基本的排序:
原本是:
[(2, 1), (1, 2)]
第一次排序以第2個元素為 key,所以排序的結果為:
[(2, 1), (1, 2)]
第二次排序以第1個元素為 key,所以排序的結果為:
[(1, 2), (2, 1)] # 最終結果
結論(1):
tuple 的排序由最後的元素往前依次進行排序
也就是說 tuple 的排序權重是由第一個元素開始依次向後遞減
接著我們來觀察一下 Boolean value 的排序:
print(sorted([True, False])
結果:
[False, True] # False在前,True在後
結論2:
Boolean 的排序會將 False
排在前,True
排在後
那我們來看看你給出的例子,我們撰寫一個簡單的 function 來觀察結果:
def show(s):
for x in s:
print((x.isdigit(), x.isdigit() and int(x)%2==0, x.isupper(), x.islower(), x))
function show
會列印出當下的字串 s
用來排序時每個字元所產生的 tuple key.
接著我們套用剛剛的結論1,我們先不使用 tuple 來作為 key,反而利用等價的 由最後一個元素往前依次為 key 排序,並且逐步觀察 s
和 tuple key 的變化:
print('key=x')
s = sorted(s ,key=lambda x: x)
show(s)
print('key=islower()')
s = sorted(s ,key=lambda x: x.islower())
show(s)
print('key=isupper()')
s = sorted(s ,key=lambda x: x.isupper())
show(s)
print('key=isdigit() and int(x)%2==0')
s = sorted(s ,key=lambda x: x.isdigit() and int(x)%2==0)
show(s)
我們將會發現一如預期地,依照結論(1),這樣的做法的確等價於一口氣以 tuple 為 key 來排序.
同時觀察,結論(2),對於 isdigit()
, isupper()
, islower()
print('key=isdigit()')
s = sorted(s ,key=lambda x: x.isdigit())
show(s)
第一次排序以第2个元素为 key,所以排序的结果为:
第二次排序以第1个元素为 key,所以排序的结果为:sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
print("".join(sorted(s1, key=lambda x: (not x.islower(), not x.isupper(), not(x.isdigit() and int(x)%2==1), x))))
结论(1):tuple 的排序由最后的元素往前依次进行排序
也就是说 tuple 的排序权重是由第一个元素开始依次向后递减
接着我们来观察一下 Boolean value 的排序:
rrreee结果:
rrreee
结论2
:Boolean 的排序会将
False
排在前,True
排在后
那我们来看看你给出的例子,我们撰写一个简单的 function 来观察结果:rrreee
functionshow
会列印出当下的字串s
用来排序时每个字元所产生的 tuple key. 🎜 🎜接着我们套用刚刚的结论1,我们先不使用tuple 来作为key,反而利用等价的🎜由最后一个元素往前依次为key 排序🎜,并且逐步观察s
和tuple key的变化:🎜 rrreee 🎜我们将会发现一如预期地,依照结论(1),这样的做法的确等价于一口气以 tuple 为 key 来排序.
同时观察,结论(2),对于isdigit()
,isupper()
,islower()
等所产生的Boolean key来说,排序的结果也如预期. 🎜 rrreee 🎜 🎜不过我想这还不是我们最后的结论,因为这是一个碰巧的结果(说碰巧也许太超过了,应该说是不那么直觉的结果),让我们根据🎜结论(1)🎜 对最初的例子进行分析:🎜 rrreee 🎜这个排序我们可以翻译成:🎜 🎜🎜先对字元x本身做排序,接着是对 字元是否为小写,字元是否为大写,字元是否为偶数,字元是否为数字分别作排序. 🎜🎜 🎜也可以翻译成:🎜 🎜🎜我们以 字元是否为数字为最高排序权重,接着以字元是否为偶数,字元是否为大写,字元是否为小写,字元x本身为权重来做排序. 🎜🎜 🎜这似乎与一开始的目标(#排序:小写-大写-奇数-偶数)不同,起码跟目标没有直觉上的对应. 🎜 🎜建议可以改成:🎜 rrreee 🎜这样就可以解读为:🎜 🎜🎜我们以 字元是否为小写为最高权重,接着以字元是否为大写,字元是否为奇数,字元x本身为权重来做排序🎜
有趣的是:我们想要让判断式为 True
的字元在排序完成後在比較前面的位置,所以根據結論(2)加了一個 not
来让符合的字元可以在前面.
高洛峰2017-04-17 17:49:14
关键之处如donghui
所说,FALSE<TRUE。donghui
所说,FALSE<TRUE。
key为元组的排序情况,是每个待排序元素生成一个元组(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x)
,排序时是根据这个元组排序,依据是FALSE<TRUE,false排前,true排后,相同则看下一个。sorted最终返回的是需要排序的元素。
测试代码如下:(来源自dokelung
和donghui
key为元组的排序情况,是每个待排序元素生成一个元组(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x)
,排序时是根据这个元组排序,依据是FALSE<TRUE,false排前,true排后,相同则看下一个。sorted最终返回的是需要排序的元素。
测试代码如下:(来源自dokelung
和donghui
)
if __name__ == '__main__':
s = 'asdf234GDSdsf23'
print('key=x')
s = sorted(s, key=lambda x: x)
for x in s:
print((x, x))
print('key=islower()')
s = sorted(s, key=lambda x: x.islower())
for x in s:
print((x.islower(), x))
print('key=isupper()')
s = sorted(s, key=lambda x: x.isupper())
for x in s:
print((x.isupper(), x))
print('key=isdigit() and int(x)%2==0')
s = sorted(s, key=lambda x: x.isdigit() and int(x) % 2 == 0)
for x in s:
print((x.isdigit() and int(x) % 2 == 0, x))
print('key=(x.isupper(), x.islower())')
s = sorted(s, key=lambda x: (x.isupper(), x.islower()))
for x in s:
print((x.isupper(), x.islower(), x))
print('key=(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))')
s = sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
for x in s:
print((x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
运行查看输入可以发现规律。🎜输出:🎜
key=x
('2', '2')
('2', '2')
('3', '3')
('3', '3')
('4', '4')
('D', 'D')
('G', 'G')
('S', 'S')
('a', 'a')
('d', 'd')
('d', 'd')
('f', 'f')
('f', 'f')
('s', 's')
('s', 's')
key=islower()
(False, '2')
(False, '2')
(False, '3')
(False, '3')
(False, '4')
(False, 'D')
(False, 'G')
(False, 'S')
(True, 'a')
(True, 'd')
(True, 'd')
(True, 'f')
(True, 'f')
(True, 's')
(True, 's')
key=isupper()
(False, '2')
(False, '2')
(False, '3')
(False, '3')
(False, '4')
(False, 'a')
(False, 'd')
(False, 'd')
(False, 'f')
(False, 'f')
(False, 's')
(False, 's')
(True, 'D')
(True, 'G')
(True, 'S')
key=isdigit() and int(x)%2==0
(False, '3')
(False, '3')
(False, 'a')
(False, 'd')
(False, 'd')
(False, 'f')
(False, 'f')
(False, 's')
(False, 's')
(False, 'D')
(False, 'G')
(False, 'S')
(True, '2')
(True, '2')
(True, '4')
key=(x.isupper(), x.islower())
(False, False, '3')
(False, False, '3')
(False, False, '2')
(False, False, '2')
(False, False, '4')
(False, True, 'a')
(False, True, 'd')
(False, True, 'd')
(False, True, 'f')
(False, True, 'f')
(False, True, 's')
(False, True, 's')
(True, False, 'D')
(True, False, 'G')
(True, False, 'S')
key=(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
(False, False, False, True, 'a')
(False, False, False, True, 'd')
(False, False, False, True, 'd')
(False, False, False, True, 'f')
(False, False, False, True, 'f')
(False, False, False, True, 's')
(False, False, False, True, 's')
(False, False, True, False, 'D')
(False, False, True, False, 'G')
(False, False, True, False, 'S')
(True, False, False, False, '3')
(True, False, False, False, '3')
(True, True, False, False, '2')
(True, True, False, False, '2')
(True, True, False, False, '4')