Python:根据第一个 None 类型对两个列表进行排序

Python: Sort Two Lists Based On First With None Types

所以我有两个列表:

keys   = ['Z', 'X', None, None]
values = [ 0 ,  1 , None, None]

我需要能够获取这两个列表并根据键值对它们进行排序,然后 return 它自己。理想情况下,输出为:

keys   = ['X', 'Z', None, None]
values = [ 1 ,  0 , None, None]

我在这里尝试的是:

self.keys, self.values = (list(x) for x in zip(*sorted(zip(self.keys, 
                          self.values), key=lambda pair: pair[0])))

这很好用,除了它给我的错误:

TypeError: unorderable types: NoneType() < str()

如何使用此方法对 None 进行排序?有比我尝试的更好的方法吗?

如果您需要让您的排序键函数在 return 值上保持一致(如果不是,您应该这样做),只需将其修改为 lambda pair: pair[0] or ""。它将在 (None, <WHATEVER>).

return ""

否则请定义是否None > "1"

只需为 sorted

的密钥添加一个条件
keys, values = (list(x) for x in zip(*sorted(zip(keys, values), key=lambda pair: pair[0] if pair[0] is not None else 'temp')))

这样做会将 'temp' 映射到列表中的任何 None 值,并且按排序的比较顺序 'temp' 大于 'X'。大写字母小于小写字母

>>> 'temp' < 'X'
False

链接的问题有一些可行的方法,但我认为错过了我的首选方法,即按 元组 键而不是标量进行排序。这样我们就可以确保我们只比较可比较的数量。

例如:

>>> list(zip(keys, values))
[('Z', 0), ('X', 1), (None, None), (None, None)]
>>> sorted(zip(keys, values),key=lambda x: (x[0] is None, x[0]))
[('X', 1), ('Z', 0), (None, None), (None, None)]

这是有效的,因为对于每一对,我们得到一个布尔值和一个字符串的元组:

>>> for pair in zip(keys, values):
...     print(pair, (pair[0] is None, pair[0]))
...     
('Z', 0) (False, 'Z')
('X', 1) (False, 'X')
(None, None) (True, None)
(None, None) (True, None)

由于元组比较的工作原理,我们只需在 True 或 False 组内进行比较,因此 None 永远不会与字符串进行比较。由于 False < True,我们将在最后得到 None 对。

另一种解决方案是拥有一些永远不会小于任何其他对象的对象,并在遇到 None.

时使用它进行比较
>>> def sortkey(pair):
...     if pair[0] is not None:
...         return pair[0]
...     return type('', (object,), {'__lt__': lambda x,y: False})()
... 
>>> keys   = ['Z', 'X', None, None]
>>> values = [ 0 ,  1 , None, None]
>>> k, v = map(list, zip(*sorted(zip(keys, values), key=sortkey)))
>>> k
['X', 'Z', None, None]
>>> v
[1, 0, None, None]

一个简单的解决方案是定义您自己的密钥

sort_fxn = lambda pair: '' if pair[0] is None else pair[0] 
list(zip(*sorted(zip(keys, values), key=sort_fxn)))

None 值未位于排序的末尾,但其他键已排序:

[(None, None, 'X', 'Z'), (None, None, 1, 0)]

如果 None 值对您的排序至关重要,您可以将所有字符串编码为字节并使用字节数组比较:

sort_fxn = lambda pair: bytes([255]) if pair[0] is None else pair[0].encode('utf-8')

注意:由于顺序的原因,这确实需要两倍的时间来排序。 (3 对 1.5 微秒)如果您担心这种优化。