【问题标题】:Python: Sort Two Lists Based On First With None TypesPython:基于无类型的第一个列表对两个列表进行排序
【发布时间】:2016-08-03 10:24:48
【问题描述】:

所以我有两个列表:

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

我需要能够获取这两个列表并根据键值对其进行排序,然后将其返回给自己。理想情况下,输出将是:

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 进行排序?有没有比我正在尝试的更好的方法?

【问题讨论】:

  • None 应该大于一切吗?
  • @LauroMoura 这个问题很接近,但它没有使用我试图实施的方法。
  • @timgeb 没错,None 应该始终留在列表的末尾

标签: python list sorting python-3.x nonetype


【解决方案1】:

另一种解决方案是拥有一个永远不会小于任何其他对象的对象,并在遇到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]

【讨论】:

    【解决方案2】:

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

    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 微秒)如果您担心这种优化。

    【讨论】:

      【解决方案3】:

      只需为 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
      

      【讨论】:

      • 正是我想要的。谢谢!
      【解决方案4】:

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

      例如:

      >>> 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

      【讨论】:

      • 我喜欢这个实现,我很想给它投票正确的答案。但是,我不想将键和值的表示从两个单独的列表更改。如果我没有这个要求,你的答案就是要走的路。
      • @Avairhn:呃,你不需要。就像您在原始代码中编写 sorted(zip(self.keys, self.values), key=lambda pair: pair[0]) 一样,您可以改用上述键功能。
      【解决方案5】:

      如果你需要让你的排序键函数在返回值上保持一致(如果不是,你应该),只需像lambda pair: pair[0] or ""一样修改它。它将在(None, &lt;WHATEVER&gt;) 上返回""

      否则请定义是否None &gt; "1"

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        • 2020-12-24
        • 2012-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多