【问题标题】:Custom compare function in python3python3中的自定义比较函数
【发布时间】:2018-03-16 18:25:46
【问题描述】:

我想按点到原点 (0,0) 的距离以升序对 2D 坐标系中的点进行排序。我找到了this 并尝试了一些方法,但仍然无法获得想要的结果。

这是我的代码:

from functools import cmp_to_key

def my_comp(point1, point2):
    return point1[0]*point1[0] + point1[1]*point1[1] < point2[0]*point2[0] + point2[1]*point2[1]

points = [ [3.1, 4.1], [0.9, 0.8], [1.0, 1.0] ]
sorted(points, key=cmp_to_key(my_comp))
print(points)

结果:

[[3.1, 4.1], [0.9, 0.8], [1.0, 1.0]]

预期:

[[0.9, 0.8], [1.0, 1.0], [3.1, 4.1]]

【问题讨论】:

  • 你得到了什么结果,为什么不符合你的预期?
  • result 是作为初始数组,想要的看起来像这样[[0.9, 0.8], [1.0, 1.0], [3.1, 4.1]]
  • 为了完整起见,您应该将其放在您的问题中。
  • 对不起,我的错。固定

标签: python python-3.x


【解决方案1】:

看起来你在这里经历了一些额外的障碍。你有一个已经是完美键的数量。您不仅可以使用它,还可以定义一个比较器,该比较器为每对对象重新计算和比较其中两个量,然后将该比较器转换回一个键。

这似乎非常低效。为什么不直接定义一个简单的按键函数直接使用呢?

def distance_from_origin_squared(point):
    return point[0]**2 + point[1]**2
points = sorted(points, key=distance_from_origin_squared)

请记住,sorted 不会就地运行,因此您必须将其存放在某个地方。如果可以,请替换原始名称。如果您想要就地排序,请改用list.sort

points.sort(key=distance_from_origin_squared)

从实用的角度来看,与比较器相比,键具有许多优势。一方面,一个关键函数只需要每个元素调用一次,而比较器调用O(nlog(n)) 次。当然,键会比较O(nlog(n)) 次,但比较通常要简单得多,因为感兴趣的值是预先计算的。

来自 C 的主要困难(在我的例子中)是理解键不必是单个整数的想法,如示例中所示。键可以是明确定义&lt;(或&gt;)运算符的任何类型。字符串、列表和元组的字典比较可以很容易地将复杂的链式比较器归结为只是一个短序列值的键。

【讨论】:

    【解决方案2】:

    1) 您的 my_cmp() 函数应该返回三个值之一(+、- 或 0,具体取决于比较),但您只返回两个值(True 和 False)。

    2) 你忽略了sorted() 的返回值。 sorted() 不修改它的参数,它返回它的排序副本。

    3) 不要使用 cmp 函数。它们很难描述,也很难实施。而是使用键功能。

    怎么样:

    def my_key(point1):
        return point1[0]*point1[0] + point1[1]*point1[1]
    
    points = [ [3.1, 4.1], [0.9, 0.8], [1.0, 1.0] ]
    points = sorted(points, key=my_key)
    print(points)
    
    assert points == [ [0.9, 0.8], [1.0, 1.0], [3.1, 4.1] ]
    

    【讨论】:

    • 先生,我错过了 sorted 函数的要点,也就是您在第二次改进中提到的那个。它不修改,它返回。 Tnx。
    【解决方案3】:

    这是你想要的吗?

    sorted_points = sorted(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
    

    在您的原始代码中要注意的另一件事是 sorted 不会对列表进行适当的排序,它会创建一个已排序的新列表。所以当你这样做时

    points = [3,2,1]
    sorted(points)
    print(points)
    

    您的代码似乎没有对任何内容进行排序,因为您打印的是原始列表而不是新创建的排序列表。您可以像这样就地执行排序。

    points = [3,2,1]
    points.sort()
    print(points)
    

    【讨论】:

    • 没有必要取平方根。删除导入并加快速度。
    【解决方案4】:

    您混淆了 cmpkey 参数。 cmp 函数接受两个参数并返回 -101key 函数返回将用于对列表进行排序的代理值。 cmp 在 Python 3 中作为 sorted 的参数被删除。

    【讨论】:

    • 好的,但是不管cmp 关键字是否存在,cmp_to_key 不应该仍然有效吗?
    • @Kevin 它会,除了 cmp 函数仍然应该返回 -1.0,1,而不是 True/False
    • @BrendanAbel。真的。它应该返回 True、False 和 -1 :) 从技术上讲 True == 1 和 False == 0。bools 是 int 的子类。
    • 另外,它不仅仅是 +/-1。任何正值或负值都可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多