python - 如何在 Python 3 中使用 "isclose"比较而不是绝对相等 (==) 对带有 float 的元组进行排序?

标签 python python-3.x sorting floating-point

我想主要按 float 排序对列表,其次按整数排序。问题在于比较 float 是否相等——在许多情况下,我们会进行任意比较,而不是诉诸二级顺序。

示例

my_list = [
  (0, 1.2),
  (2, 0.07076863960397783),
  (1, 0.07076863960397785),
  (4, 0.02)
]

我想主要按浮点值排序,其次按整数排序。 运行 sorted(my_list, key=lambda x: (x[1], x[0])) 返回:

[(4, 0.02), (2, 0.07076863960397783), (1, 0.07076863960397785), (0, 1.2)]

但是由于两个 float 非常接近,因此它们实际上应该被视为相等,因此所需的顺序是这样的:

[(4, 0.02), (1, 0.07076863960397785), (2, 0.07076863960397783), (0, 1.2)]

如何将 math.isclosenp.isclose 合并到排序中?

我的尝试

我当前的方法是将 float 包装到一个类中,该类使用 numpy 的 isclose 执行比较。

class FloatComparisonWrapper:
    def __init__(self, num):
        self.value = num

    def __lt__(self, other):
        return self.__ne__(other) and self.value < other.value

    def __gt__(self, other):
        return self.__ne__(other) and self.value > other.value

    def __eq__(self, other):
        return np.isclose(self.value, other.value)

    def __ne__(self, other):
        return not self.__eq__(other)

    def __le__(self, other):
        return self.__eq__(other) or self.value <= other.value

    def __ge__(self, other):
        return self.__eq__(other) or self.value >= other.value

然后 sorted(my_list, key=lambda x: (FloatComparisonWrapper(x[1]), x[0])) 给出正确的排序。

这是一个好的解决方案吗?它是 python 式的吗?这是最好的解决方案吗?有没有更快的方法?

最佳答案

Is this a good solution?

没有。
OP 的方法在排序方面存在缺陷。

since the two floats are so close that they should really be considered equal

考虑所有值是否都接近同一浮点值。有些对是“相等的”,有些则不是。 OP 的目标失败,因为比较没有形成 Total order .


从 C 的角度来看,这可能适用于 Python,因为我认为这个问题与语言无关。

这不会像compare(a, b)那样工作, compare(b,c) , compare(a,c)必须形成一致的顺序。

When the same objects (consisting of size bytes, irrespective of their current positions in the array) are passed more than once to the comparison function, the results shall be consistent with one another. That is, for qsort they shall define a total ordering on the array, ... C1723 § 7.24.5 4.

考虑

(2, float_before(x)), // Lowest value that "is close" to x.
(1, x),
(0, float_after(x)), // Greatest value that "is close" to x.

尽管float_before(x)x是连续的“相等”值,如OP建议的(以及 xfloat_after(x) ),排序将得到不同的(并且可能不确定:例如无限循环)结果,具体取决于应用比较的顺序自 compare(float_before(x), float_after(x))不相等。


除非一阶值相等,否则不应应用二次比较。几乎等于 a ≈ b 是不够的和b ≈ c可能是真的,但是a ≈ c不是。

与 OP 几乎相同,a > bb > c由于它们的主要比较相等,但次要比较使它们大于有序值,并且意味着 a > c 。然而自从a不接近c主要排序是 a < c 。这与a > c相矛盾.


Is there a quicker way to do it?

我建议删除 isclose() “两个 float 非常接近,以至于它们确实应该被视为相等”的主要比较方法。只需进行值(value)比较即可。在尝试加快速度之前先确保功能正确。

// Pseudo code
if (primary_compare_as_equal(a,b))
  return secondary compare(a,b)
return primary_compare(a,b)

关于python - 如何在 Python 3 中使用 "isclose"比较而不是绝对相等 (==) 对带有 float 的元组进行排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76924742/

相关文章:

python - 为什么我会收到无效的 block 标签 : 'static' error?

python - 装饰器,不带括号调用函数?

python-3.x - 给定该文件的路径,如何使用 python 关闭在 windows 上的 excel 应用程序中打开的一个特定 csv 文件?

Python3 元类 : use to validate constructor argument

python - 排序没有内置排序、最小值、最大值函数的数字列表

java - Java 合并排序算法的问题

python - 为什么在启动程序时我的通知区域图标不显示?

python - Perl 正则表达式与 Python 正则表达式非捕获似乎工作方式不同

python - 有什么办法可以防止这个递归函数将初始数字添加到总数中

java - 时间和/或日期排序