在 python 中使用 ord() 和 lambda 排序

Usage of sorted with ord() and lambda in python

我在 Hackerrank 上做了一个练习,在讨论中我偶然发现了一个非常好的单行解决方案来解决以下问题:

S 是一个字母数字字符串,您必须使用以下规则对其进行排序:

  1. 所有排序的小写字母都在大写字母之前。
  2. 所有排序的大写字母都在数字之前。
  3. 所有排序的奇数位都排在排序的偶数位之前。

提供的解决方案是:

print(*sorted(input(), key=lambda c: (-ord(c) >> 5, c in '02468', c)), sep='')

现在,我了解了 lambda 和 ord 的工作原理,我想正确理解这段代码,所以我做了以下工作来理解它:

b = "Sorting1234"
print(*sorted(input(), key=lambda c: (ord(c))), sep='')

输出:

['1', '2', '3', '4', 'S', 'g', 'i', 'n', 'o', 'r', 't']

因此,这段代码根据 ASCII 码对给定的字符串进行排序。现在,我们希望先有小写字母,然后是大写字母,然后是数字,所以我们现在颠倒这个顺序:

sorted(b,key=lambda x: (-ord(x)))

输出:

['t', 'r', 'o', 'n', 'i', 'g', 'S', '4', '3', '2', '1']

现在,这部分我不明白,我们为什么要使用二进制移位运算符,它有什么作用?

sorted(b,key=lambda x: (-ord(x)>>3))

输出:

['r', 't', 'o', 'i', 'n', 'g', 'S', '1', '2', '3', '4']

现在右移 5:

sorted(b,key=lambda x: (-ord(x)>>5))

输出:

['o', 'r', 't', 'i', 'n', 'g', 'S', '1', '2', '3', '4']

我们甚至还没有达到我们实际想要的一半,但完整的代码突然产生了正确的答案:

sorted(b,key=lambda x: (-ord(x)>>5, x in '02467', x))

输出:

['g', 'i', 'n', 'o', 'r', 't', 'S', '1', '3', '2', '4']

看ASCII码table,128个字符排成四列,每列32个(这里只显示printable个字符):

  0      32      64 @    96 `   
  1      33 !    65 A    97 a   
  2      34 "    66 B    98 b   
  3      35 #    67 C    99 c   
  4      36 $    68 D   100 d   
  5      37 %    69 E   101 e   
  6      38 &    70 F   102 f   
  7      39 '    71 G   103 g   
  8      40 (    72 H   104 h   
  9      41 )    73 I   105 i   
 10      42 *    74 J   106 j   
 11      43 +    75 K   107 k   
 12      44 ,    76 L   108 l   
 13      45 -    77 M   109 m   
 14      46 .    78 N   110 n   
 15      47 /    79 O   111 o   
 16      48 0    80 P   112 p   
 17      49 1    81 Q   113 q   
 18      50 2    82 R   114 r   
 19      51 3    83 S   115 s   
 20      52 4    84 T   116 t   
 21      53 5    85 U   117 u   
 22      54 6    86 V   118 v   
 23      55 7    87 W   119 w   
 24      56 8    88 X   120 x   
 25      57 9    89 Y   121 y   
 26      58 :    90 Z   122 z   
 27      59 ;    91 [   123 {   
 28      60 <    92 \   124 |   
 29      61 =    93 ]   125 }   
 30      62 >    94 ^   126 ~   
 31      63 ?    95 _   127     

将列编号为 0 到 3,您将在第 1 列中找到数字,在第 2 列中找到大写字母,在第 3 列中找到小写字母。

右移5相当于除以32并向下取整。所以 ord(c) >> 5 会给你列号 1、2 或 3,具体取决于类型 digit/upper/lower。因为我们想要 reversed 顺序,所以我们取反。

实际表达式 -ord(c) >> 5 否定 first(如空格所示),这会稍微改变一下:顶行(代码为 0、32、 64 和 96) 得到错误的列号。但是那些字符与我们无关。