Python3样式排序 - 旧密钥机制中的旧cmp方法功能?

fyn*_*yrz 2 python sorting

我读到了包装器函数,它将cmp样式比较转换为Python 3中的键样式比较,其中删除了cmp功能.

我有一点时间围绕Python3直键样式sorted()函数的方式,至少据我所知,只有一个为键指定的项目,可以让你正确比较,例如,两个IP用于订购.或火腿电话.

而对于cmp,它没有任何东西:sorted()和sort()用两个ips调用你,你查看了相应的部分,完成了你的决定.

def ipCompare(dqA,dqB):
    ...

ipList = sorted(ipList,cmp=ipCompare)
Run Code Online (Sandbox Code Playgroud)

火腿无线电呼叫也是如此.排序不是字母; 电话通常是字母+数字+字母; 第一个排序优先级是数字部分,然后是第一个字母,然后是最后一个字母(s.)

使用cmp ......没有汗水.

def callCompare(callA,callB):
    ...

hamlist = sorted(hamlist,cmp=callCompare)
Run Code Online (Sandbox Code Playgroud)

使用Python3 ...没有经过包装器的箍跳......并且通过了一个项目......我想......怎么能这样做?

如果绝对需要包装器...那么为什么首先在Python3中删除cmp?

我确定我错过了什么.我只是看不到它.:/


好的,现在我知道我错过了什么.解决方案IPs在下面的答案中给出.这是我提出的用于排序公共前缀,区域,后缀形式的火焰调用的密钥:

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)
Run Code Online (Sandbox Code Playgroud)

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

详情:

  • AA7AS出来的callKey()作为7,AA,AS
  • N4EJI出来的callKey()作为4,N,EJI
  • W1AW出来的callKey()作为1,W,AW
  • na1a出来的callKey()作为1,NA,A

aba*_*ert 5

首先,如果你还没有读过Sorting HOWTO,那一定要读一下; 它解释了很多一开始可能并不明显的事情.


对于您的第一个示例,两个IPv4地址,答案非常简单.

要比较两个地址,一个显而易见的事情是将它们从点四个字符串转换为4个整数的元组,然后只比较元组:

def cmp_ip(ip1, ip2):
    ip1 = map(int, ip1.split('.'))
    ip2 = map(int, ip2.split('.'))
    return cmp(ip1, ip2)
Run Code Online (Sandbox Code Playgroud)

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

def cmp_ip(ip1, ip2):
    return cmp(ipaddress.ip_address(ip1), ipaddress.ip_address(ip2))
Run Code Online (Sandbox Code Playgroud)

很明显,这些作为关键功能更容易:

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

def key_ip(ip):
    return ipaddress.ip_address(ip)
Run Code Online (Sandbox Code Playgroud)

对于你的第二个例子,火腿无线电呼号:为了写一个cmp功能,你必须能够将每个火腿地址分成字母,数字,字母部分,然后比较数字,然后比较第一个字母,然后比较第二个字母字母.为了编写一个key函数,你必须能够将一个火腿地址分解成字母,数字,字母部分,然后返回一个元组(数字,第一个字母,第二个字母).关键功能实际上更容易,而不是更难.


实际上,大多数人都能想到的例子就是这种情况.最复杂的比较最终归结为复杂的部分序列转换,然后是该序列的简单词典比较.

这就是为什么cmp函数在2.4中被弃用并最终在3.0中删除的原因.


当然,在某些情况下,cmp功能更容易阅读 - 人们试图提出的大多数示例都是错误的,但也有一些.而且还有代码已经工作了20年,没有人想以新的方式重新考虑它,没有任何好处.对于那些情况,你已经有了cmp_to_key.


实际上还有另一个原因cmp被弃用了,除此之外,可能还有三分之一.

在Python 2.3中,类型有一个__cmp__方法,用于处理所有运算符.在2.4中,他们长大了六种方法__lt__,__eq__等作为替代.这样可以提供更大的灵活性 - 例如,您可以拥有非全部订购的类型.所以,2.3比较时a < b,它实际上正在做a.__cmp__(b) < 0,它以一种非常明显的方式映射到一个cmp参数.但是在2.4+ a < ba.__lt__(b),确实没有.多年来,这让很多人感到困惑,并且删除这两者__cmp__以及cmp排序函数的参数消除了这种混乱.

同时,如果您阅读排序HOWTO,您会注意到在我们开始之前cmp,做这种事情的唯一方法是decorate-sort-undecorate(DSU).请注意,如何将一个好的key函数映射到一个好的DSU排序,反之亦然,这显然是显而易见的,但对于一个cmp函数来说,它绝对不是很明显.我不记得有人在py3k列表中明确提到过这个,但我怀疑在决定是否最终杀死时,人们可能已经有了这个cmp.

  • @fyngyrz:是的,在每个元素上调用`key`函数,并比较结果.(另请注意,大多数操作 - 特别是在`list.sort`中 - 保证它只会在每个元素上被调用一次.结果会被缓存到一个你不必担心的神奇地方.这也意味着使用`key`函数类似于decorate-sort-undecorate方法,我们必须在真正老的Python中使用它.) (2认同)