sorted([2, float('nan'), 1])
返回[2, nan, 1]
(至少在Activestate Python 3.1实现上。)
我理解nan
是一个奇怪的对象,所以如果它出现在排序结果中的随机位置,我不会感到惊讶。但它也混淆了容器中非纳米数的排序,这真是出乎意料。
我向related question询问了max
,基于此我理解为什么sort
会像这样工作。但这应该被视为一个错误吗?
文档只是说“返回一个新的排序列表[...]”而没有指定任何细节。
编辑: 我现在同意这不违反IEEE标准。但是,我认为这是任何常识观点的错误。即使微软经常承认自己的错误,也已经认识到这个错误,并将其修复为最新版本:http://connect.microsoft.com/VisualStudio/feedback/details/363379/bug-in-list-double-sort-in-list-which-contains-double-nan。
无论如何,我最终关注了@ khachik的回答:
sorted(list_, key = lambda x : float('-inf') if math.isnan(x) else x)
我怀疑它与默认情况下的语言相比会导致性能下降,但至少它会起作用(除非我介绍的任何错误)。
答案 0 :(得分:12)
以前的答案很有用,但可能不清楚问题的根源。
在任何语言中,sort都应用由比较函数或以其他方式定义的给定排序,而不是输入值的域。例如,当且仅当小于定义输入值的合适排序时,可以使用小于a.k.a。operator <,
。
但对于浮点值而言,这尤其不适用于:
“NaN是无序的:它不等于,大于或小于任何东西,包括它自己。” (来自GNU C手册的清晰散文,但适用于所有现代IEEE754
基于浮动点)
所以可能的解决方案是:
- 首先删除NaN,使输入域通过&lt; (或正在使用的其他排序功能)
- 定义一个自定义比较函数(a.k.a。谓词) 定义NaN的排序,例如小于任何数字或更大 比任何数字都要多。
醇>
任何一种语言都可以使用。
实际上,考虑到python,如果你不关心最快的性能,或者如果在上下文中删除NaN是一种理想的行为,我宁愿删除NaN。
否则,您可以在较旧的python版本中通过“cmp”使用合适的谓词函数,或通过此functools.cmp_to_key()
使用。后者比首先去除NaN更加尴尬。在定义此谓词函数时,需要注意避免更差性能。
答案 1 :(得分:7)
问题是如果列表包含NAN,则没有正确的顺序,因为如果a1&lt; = a2&lt; = a3&lt; = ...,则序列a1,a2,a3,...,a被排序。 &lt; = an。如果这些值中的任何一个是NAN,则排序的属性会中断,因为对于所有a,&lt; = NAN和NAN&lt; = a都是假的。
答案 2 :(得分:5)
我不确定该错误,但解决方法可能如下:
sorted(
(2, 1, float('nan')),
lambda x,y: x is float('nan') and -1
or (y is float('nan') and 1
or cmp(x,y)))
导致:
('nan', 1, 2)
或者在排序或其他任何内容之前删除nan
。
答案 3 :(得分:3)
IEEE754是在此实例中定义浮点运算的标准。该标准定义了操作数的比较操作,其中至少有一个是NaN,是一个错误。因此,这不是一个错误。在对阵列进行操作之前,您需要处理NaN。
答案 4 :(得分:0)
假设你想保留NaN并将它们命名为最低的“值”,这里有一个解决方法,使用非唯一的纳米,独特的numpy nan , 数字和非数字对象:
def is_nan(x):
return (x is np.nan or x != x)
list_ = [2, float('nan'), 'z', 1, 'a', np.nan, 4, float('nan')]
sorted(list_, key = lambda x : float('-inf') if is_nan(x) else x)
# [nan, nan, nan, 1, 2, 4, 'a', 'z']
答案 5 :(得分:0)
不管标准是什么,在许多情况下,用户定义的float和NA
值顺序都是有用的。例如,我正在对股票收益进行排序,并希望从最后到NA
从高到低(因为这些无关紧要)。有4种可能的组合
NA
个值NA
个值NA
个值NA
个值此功能涵盖了所有情况,方法是将NA
的值有条件地替换为+/- inf
import math
def sort_with_na(x, reverse=False, na_last=True):
"""Intelligently sort iterable with NA values
For reliable behavior with NA values, we should change the NAs to +/- inf
to guarantee their order rather than relying on the built-in
``sorted(reverse=True)`` which will have no effect. To use the ``reverse``
parameter or other kwargs, use functools.partial in your lambda i.e.
sorted(iterable, key=partial(sort_with_na, reverse=True, na_last=False))
:param x: Element to be sorted
:param bool na_last: Whether NA values should come last or first
:param bool reverse: Return ascending if ``False`` else descending
:return bool:
"""
if not math.isnan(x):
return -x if reverse else x
else:
return float('inf') if na_last else float('-inf')
分别测试4种组合
from functools import partial
a = [2, float('nan'), 1]
sorted(a, key=sort_with_na) # Default
sorted(a, key=partial(sort_with_na, reverse=False, na_last=True)) # Ascend, NA last
sorted(a, key=partial(sort_with_na, reverse=False, na_last=False)) # Ascend, NA first
sorted(a, key=partial(sort_with_na, reverse=True, na_last=True)) # Descend, NA last
sorted(a, key=partial(sort_with_na, reverse=True, na_last=False)) # Descend, NA first
答案 6 :(得分:0)
弹性排序涉及比较 2 个项目并返回:less、equal、greater。
如果 cmp(a,b)
是“更大”,那么 cmp(b,a)
必须是“更少”。
如果 cmp(a,b)
为“零”,则 cmp(b,a)
必须为“零”。
迄今为止的答案中缺少的是比较 2 个 float
的情况,这些 if isnan(a)
if isnan(b)
return 0 (or maybe compare payloads/bit patterns)
return 1
if isnan(b) return 1
if a > b return 1
if a < b return -1
return 0
都是 NAN 并保留了上述属性。 2 个 NAN 的比较应该相等,或者可能基于对其有效载荷的一些一致解释。
Alternate compare algorithm 把所有的 NAN > +inf
(ns test
(:require [io.pedestal.http :as http]
[io.pedesteal.http.route :as route]))