Python3风格排序--在新的键机制中使用旧的cmp方法功能?

2024-07-04 17:13:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我在python3中读到了将cmp样式比较移到键样式比较中的包装器函数,其中去掉了cmp功能。在

我花了很长时间来思考Python3 straight key style sorted()函数,至少据我所知,只为键指定一个项,就可以让您正确地比较,例如,两个IP进行排序。或者打电话。在

而对于cmp则没有任何用处:sorted()和sort()用两个IP调用了您,您查看了适当的部分,做出了决定,完成了。在

def ipCompare(dqA,dqB):
    ...

ipList = sorted(ipList,cmp=ipCompare)

无线电通话也是一样。排序不是按字母排序的;调用一般是字母+数字+字母;第一个排序优先级是数字部分,然后是第一个字母,最后一个字母

使用cmp。。。别担心。在

^{pr2}$

用Python3。。。不用经历包装的跳跃。。。被传递一个项目。。。我想。。。怎么能做到呢?在

如果包装是绝对必要的。。。那么为什么首先要去除Python3中的cmp呢?在

我肯定我错过了什么。我就是看不见。:/


好吧,现在我知道我错过了什么。下面的答案给出了IPs的解决方案。我想出了一个键来对常见前缀、区域、后缀形式的ham调用进行排序:

import re

def callKey(txtCall):
    l = re.split('([0-9]*)',txtCall.upper(),1)
    return l[1],l[0],l[2]

hamList = ['N4EJI','W1AW','AA7AS','na1a']

sortedHamList = sorted(hamList,key=callKey)

sortedHamList结果是['na1a','W1AW','N4EJI','AA7AS']

详细信息:

  • AA7AScallKey()的形式出现{}
  • N4EJIcallKey()出来,作为4,N,EJI
  • W1AWcallKey()的形式出现在1,W,AW
  • na1acallKey()的形式出现在1,NA,A

Tags: key函数ip排序字母样式形式python3
3条回答

要使用the new ^{} argument,只需将比较分解为已实现有序比较的另一个对象,例如元组或列表(例如整数序列)。这些类型之所以工作良好,是因为它们是按顺序排列的。在

def ip_as_components (ip):
    return map(int, ip.split('.'))

sorted_ips = sorted(ips, key=ip_as_components)

每个组件的顺序与传统比较然后按函数比较的单个测试相同。

看看火腿的点菜,你会发现:

^{pr2}$

key方法(与其他语言中的“order by”类似)通常是一个更简单、更自然的构造来处理-假设原始类型是而不是已经很好地排序了。这种方法的主要缺点是部分反转(例如asc-then-desc)排序可能很棘手,但这可以通过返回嵌套元组等来解决

In Py3.0, the cmp parameter was removed entirely (as part of a larger effort to simplify and unify the language, eliminating the conflict between rich comparisons and the __cmp__() magic method).

如果绝对需要带有自定义“cmp”的sorted,则可以简单地使用^{}。在

sorted_ips = sorted(ips, key=functools.cmp_to_key(ip_compare))

首先,如果你还没读过Sorting HOWTO,一定要读它;它解释了很多起初可能并不明显的东西。在


对于第一个示例,两个IPv4地址,答案非常简单。在

要比较两个地址,一件显而易见的事情就是将它们从虚线的四个字符串转换成4个整数的元组,然后比较这些元组:

def cmp_ip(ip1, ip2):
    ip1 = map(int, ip1.split('.'))
    ip2 = map(int, ip2.split('.'))
    return cmp(ip1, ip2)

更好的方法是将它们转换为某种表示IP地址并具有比较运算符的对象。在3.4+中,stdlib内置了这样一个对象;让我们假设2.7也这样做了:

^{pr2}$

很明显,作为关键功能,这些功能更为简单:

def key_ip(ip):
    return map(int, ip.split('.'))

def key_ip(ip):
    return ipaddress.ip_address(ip)

对于第二个例子,ham radio callsigns:为了编写cmp函数,您必须能够将每个ham地址分成字母、数字、字母部分,然后比较数字,然后比较第一个字母,然后比较第二个字母。为了编写key函数,必须能够将ham地址分解为字母、数字、字母部分,然后返回一个元组(数字、第一个字母、第二个字母)。同样,关键功能实际上是更容易,而不是更难。在


事实上,这是所有人都能想到的大多数例子的例子。大多数复杂的比较最终归结为一个复杂的部分序列的转换,然后对这个序列进行简单的词典编纂比较。在

这就是为什么cmp函数早在2.4就被弃用了,最后在3.0中被删除了。在


当然,在某些情况下,cmp函数更容易阅读,人们试图想出的大多数例子都是错误的,但也有一些。还有一些代码已经运行了20年了,没有人想用新的术语来重新考虑它而没有任何好处。对于这些情况,你有^{}。在


实际上还有另一个原因cmp被否决,在这个原因之上,也许还有第三个原因。在

在Python2.3中,类型有一个__cmp__方法,用于处理所有运算符。在2.4中,他们将六种方法__lt____eq__等作为替代。这样可以获得更大的灵活性—例如,您可以使用未完全排序的类型。所以,2.3比较a < b,它实际上是在做a.__cmp__(b) < 0,它以非常明显的方式映射到cmp参数。但是在2.4+中,a < b做了a.__lt__(b),这并没有。多年来这让很多人感到困惑,去掉{}和{}排序函数的参数消除了这种混乱。在

同时,如果您阅读排序HOWTO,您会注意到在cmp之前,完成这类操作的唯一方法是decorate sort undecorate(DSU)。请注意,如何将一个好的key函数映射到一个好的DSU排序(反之亦然)是盲目明显的,但是对于cmp函数来说,这绝对不明显。我不记得有人在py3k列表中明确提到过这一点,但我怀疑人们在决定是否最终永久性地杀死cmp时,可能已经有了这种想法。在

根据官方文件-https://docs.python.org/3/howto/sorting.html#the-old-way-using-the-cmp-parameter

When porting code from Python 2.x to 3.x, the situation can arise when you have the user supplying a comparison function and you need to convert that to a key function. The following wrapper makes that easy to do:

def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K:
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

To convert to a key function, just wrap the old comparison function:

^{pr2}$

相关问题 更多 >

    热门问题