如何在Python 3中使用自定义比较功能?


98

Python 2.x中,我可以将自定义函数传递给sort和.sort函数

>>> x=['kar','htar','har','ar']
>>>
>>> sorted(x)
['ar', 'har', 'htar', 'kar']
>>> 
>>> sorted(x,cmp=customsort)
['kar', 'htar', 'har', 'ar']

因为用我的语言,辅音是伴随着这个顺序

"k","kh",....,"ht",..."h",...,"a"

但是在Python 3.x中,看起来我无法传递cmp关键字

>>> sorted(x,cmp=customsort)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'cmp' is an invalid keyword argument for this function

有其他选择吗?或者我也应该编写自己的排序函数吗?

注意:我通过使用“ k”,“ kh”等进行了简化。实际字符是Unicode,甚至更复杂,有时在辅音前后都有元音,所以我完成了自定义比较功能,因此这一部分还可以。唯一的问题是我无法将自定义比较功能传递给sort或.sort


你试过了sorted(x)吗?
SilentGhost

@SilentGhost,为确定起见,我只是再次尝试了,当然不能用,因为操作系统在的语言列表中不支持我的原始语言来进行排序。

1
您可以将cmp包装为关键功能。在HowToSorting网站上搜索cmp_to_key。
Frank

Answers:


50

使用key参数(并按照配方上如何将旧的转换cmp功能的key功能)。

functoolscmp_to_keydocs.python.org/3.6/library/functools.html#functools.cmp_to_key中提到了一个功能


+1,看起来像是配方给了我一个解决方法,但是我认为通过将所有比较运算符传递< > = 给中间人,我会失去一些性能,因为我的原始自定义排序是用C编写的,它的速度约为C的1/2倍。默认排序。

2
(仅查看​​您的个人资料)您的公司正在阻止对Google和StackOverflow的访问?他们会变得多么愚蠢?但是关于您的回应:我会对实际性能下降感兴趣。可以timeit
Tim Pietzcker 2010年

4
我已经做了一些基准测试,看起来比直接传递自定义C比较函数慢了大约4倍。

2
如果我既需要按键功能又需要cmp功能怎么办?我想按每个词典中的自定义键对词典列表进行排序。sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)给出TypeError:'cmp'是此函数的无效关键字参数,在Python 3.2中:(
bitek 2014年

4
functools在标准库中具有cmp_to_key函数:docs.python.org/3.6/library/functools.html –MartínFixman
2016年


17

而不是customsort(),您需要一个函数来将每个单词转换为Python已经知道如何排序的东西。例如,您可以将每个单词转换为数字列表,其中每个数字代表每个字母在字母表中的位置。像这样:

my_alphabet = ['a', 'b', 'c']

def custom_key(word):
   numbers = []
   for letter in word:
      numbers.append(my_alphabet.index(letter))
   return numbers

x=['cbaba', 'ababa', 'bbaa']
x.sort(key=custom_key)

由于您的语言包括多字符字母,因此您的custom_key函数显然需要更加复杂。那应该给您大致的想法。


谢谢+1,我认为这就是ICU的方式。但是由于我的语言没有单词分隔符,也没有标准的罗马化规则,因此我认为需要花费一些时间进行研究。

9

完整的python3 cmp_to_key lambda示例:

from functools import cmp_to_key

nums = [28, 50, 17, 12, 121]
nums.sort(key=cmp_to_key(lambda x, y: 1 if str(x)+str(y) < str(y)+str(x) else -1))

与普通对象排序相比:

class NumStr:
    def __init__(self, v):
        self.v = v
    def __lt__(self, other):
        return self.v + other.v < other.v + self.v


A = [NumStr("12"), NumStr("121")]
A.sort()
print(A[0].v, A[1].v)

A = [obj.v for obj in A]
print(A)

4

我不知道这是否有帮助,但是您可以签出该locale模块。看起来您可以将语言环境设置为您的语言,并使用locale.strcoll您的语言的排序规则来比较字符串。


对流行的语言来说确实如此,但是我的语言不受操作系统,ICU和unicode.org的完全支持,因此就不成问题了,但是+1代表了很好的建议。

-2

请改用key参数。它采用一个函数,该函数接受要处理的值,并返回单个值,该值给出了用于排序的键。

sorted(x, key=somekeyfunc)

3
键只接受一个参数函数,cmp有两个参数,它们是不同的行为。我只是测试,得到了错误,因为关键的关键字只能传递一个参数TypeError: customsort() takes exactly 2 positional arguments (1 given)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.