【问题标题】:How to use a custom comparison function in Python 3?如何在 Python 3 中使用自定义比较函数?
【发布时间】:2011-02-01 16:22:43
【问题描述】:

Python 2.x 中,我可以将自定义函数传递给 sorted 和 .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”等进行了简化。实际字符是Unicodes,甚至更复杂,有时元音在辅音前后,我做了自定义比较功能,所以那部分没问题。唯一的问题是我无法将自定义比较函数传递给 sorted 或 .sort

【问题讨论】:

  • 你试过sorted(x)吗?
  • @SilentGhost,为了确保,我又试了一次,当然不行,因为 my 原始语言不在操作系统支持的区域设置列表中进行排序。
  • 您可以将您的 cmp 包装为一个关键函数。在 HowToSorting 站点中搜索 cmp_to_key。

标签: python sorting python-3.x


【解决方案1】:

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

sorted(x, key=somekeyfunc)

【讨论】:

  • key只接受一个参数函数,cmp有2个参数,它们是不同的行为。我刚刚测试,出错了,因为 key 关键字只传递一个参数,TypeError: customsort() takes exactly 2 positional arguments (1 given)
【解决方案2】:

使用key 参数(并按照recipe 了解如何将旧的cmp 函数转换为key 函数)。

functools 有一个函数cmp_to_keydocs.python.org/3.6/library/functools.html#functools.cmp_to_key 中提到

【讨论】:

  • +1,看起来配方给了我一个解决方法,但我认为通过将所有比较运算符 &lt; &gt; = 传递给中间人,我会失去一些性能,因为我原来的自定义排序是写的在 C 中,它的速度大约是默认排序的 1/2 倍。
  • (刚刚查看了您的个人资料)您的公司阻止访问 Google 和 StackOverflow?他们能蠢到什么地步?但是关于您的回复:我会对实际性能下降感兴趣。可以timeit吗?
  • 我做了一些基准测试,看起来比直接传递自定义 C 比较函数慢了大约 4 倍。
  • 如果我需要一个 key 函数和一个 cmp 函数怎么办?我想通过每个字典中的自定义键对字典列表进行排序。 sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm) 给出 TypeError: 'cmp' is an invalid keyword argument for this function, in Python 3.2 :(
  • functools 在标准库中有一个 cmp_to_key 函数:docs.python.org/3.6/library/functools.html
【解决方案3】:

您需要一个函数来代替 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 的方式。但由于 my 语言没有单词分隔符,也没有标准的罗马化规则,我认为这需要时间来研究。
【解决方案4】:

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

【讨论】:

  • 这适用于流行语言,但操作系统、ICU 和 unicode.org 不完全支持 my 语言,所以这是毫无疑问的,但是 +1 表示好的建议.
【解决方案5】:

使用key 关键字和functools.cmp_to_key 转换您的比较函数:

sorted(x, key=functools.cmp_to_key(customsort))

【讨论】:

    【解决方案6】:

    一个完整的 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多