在计算机科学中, 排序算法 列表 中的元素 按特定 order 。它们很重要,因为它们通常可以降低问题的复杂性。让我们来了解如何使用自定义排序函数在 Python 中实现自定义顺序和比较。

在我之前关于 在 Python 中使用流的 和 list.sort() 的排序方法 sorted() 。 list.sort() sorted() 都有一个关键参数,该参数指定在进行比较之前在每个列表元素上调用一个函数。

在本文中,我想进一步讨论排序主题,并探索如何在 Python 中编写自定义排序函数。换句话说,我将解释如何使用自定义 lambda 函数作为关键参数。

那么在深入阅读本文之前, 最好先阅读 如何在 Python 中定义函数

使用 Python 中的自定义排序函数进行排序

sort() 之间的区别 sorted() 。从语法上讲, sort() 是实例方法实现为 list_to_sort.sort() ,而 则 sorted() 用作 sorted(list_to_sort) .

需要注意的一件重要事情是 sort() 直接修改初始变量,因此初始顺序将会丢失。

另一方面, sorted() 保留初始变量的副本,这样就可以在需要时恢复到初始顺序。 由于 sort() 不复制任何初始变量,因此它比 更高效 sorted() 。 但是,这是以牺牲便利性为代价的。

还需要注意的是 sorted() 将返回一个列表;因此,您必须将输出分配给一个新变量。

至于 list.sort() ,它会就地修改列表,并且没有返回值。最后但同样重要的是, list.sort() 只能对列表起作用,而 sorted() 接受任何可迭代对象。

例如,这是一个不区分大小写的字符串比较:

>>> sorted(" is awesome to learn about custom sort functions in Python".split(), key=str.lower)
['about', 'awesome', 'custom', 'functions', 'in', 'is'
 'Learn', '', 'Python', 'sort', 'to']

注意: 在 Python 中,通常将自定义 lambda 函数作为关键参数传递,以对复杂对象进行排序。

现在,让我们讨论一下 Python 中的自定义排序函数。在 Python 中,我们可以编写与 sort() sorted() .

key 参数的值应为一个函数,该函数接受单个参数并返回一个 key 用于排序的函数。由于 key 函数对于每个输入记录仅调用一次,因此这是在 Python 中执行排序的有效方法。

一种常见的模式是使用对象的一些索引对复杂对象进行排序 key 。例如,我们可以定义自定义顺序来对元组列表进行排序:

>>> pokemon = [
...    ('Charmander', 'Fire', 52),
...    ('Blastoise', 'Water', 83),
...    ('Beedrill', 'Poison', 90),
... ]
>>> sorted(pokemon, key=lambda x: x[2])   # sort by attack power
[('Charmander', 'Fire', 52),
 ('Blastoise', 'Water', 83),
 ('Beedrill', 'Poison', 90)]

它也适用于具有名称属性的对象:

>>> class Pokemon:
...    def __init__(self, name, category, attack):
...        self.name = name
...        self.category = category
...        self.attack = attack
...    def __repr__(self):
...        return repr((self.name, self.category, self.attack))



>>> pokemon_objects = [
...    Pokemon('Beedrill', 'Poison', 90),
...    Pokemon('Charmander', 'Fire', 52),
...    Pokemon('Blastoise', 'Water', 83),
...            ]
>>> sorted(pokemon_objects, key=lambda x: x.attack)   # sort by attack
[('Charmander', 'Fire', 52),
 ('Blastoise', 'Water', 83),
 ('Beedrill', 'Poison', 90)]

您可以在文章《 在 Python 中创建自己的类的简单步骤》 .

了解如何操作数据、用 Python 编写自定义排序函数以及执行自定义比较是必须掌握的技能。我们的“ 数据科学 Python 入门” 是掌握这一热门技能的绝佳方式。

使用 Python 中的排序函数进行自定义比较

您还可以使用 sorted() 自定义比较器作为其参数。

在Python 2中, sorted() cmp 来实现 key

需要注意的是, cmp 需要传递两个参数(x 和 y),它们是列表的一部分。它将返回一个数字,逻辑如下:

  • 如果返回正数:x > y
  • 如果返回 0: x == y
  • 如果返回负数:x < y

但是, key 接收一个参数,计算结果,然后利用计算结果进行排序和比较。这意味着在 Python 2 中,您可以用两种不同的方式按立方值对数字列表进行排序:

>>> l = [6, 8, 10, 23, -4, -7]
>>> # The cmp parameter has been removed in Python 3
>>> sorted_l = sorted(l, cmp=lambda x, y: x ** 3 - y ** 3) # Sort with cmp
>>> sorted_l = sorted(l, key=lambda x: x ** 3) # Sort with key
>>> print(sorted_l)
[-7, -4, 6, 8, 10, 23]

在Python 3中,该 cmp 参数已被删除,主要有两个原因。

首先,用 完成的所有事情 cmp 都可以用 完成 key 。其次, key 它比 更快 cmp 。当 cmp 作为参数传递时,排序算法会比较成对的值,并且对每个项目调用多次比较函数。

另一方面,key 只执行一次计算。因此,复杂性降低了。由于语法简化,这使得代码不易出错。(在 key 之前,可以通过遵循 Decorate-Sort-Undecorate 原则(也称为 Schwartzian 变换 。)

如果你熟悉 Java 或 C++,你可能对 cmp key 。事实上,在 Python 3 中,你可以使用 cmp with func为ols.cmp_to_key(func) ,它将转换 cmp to key 。让我们在下一节中进一步探讨这一点。

在 Python 中自定义排序函数 functools.cmp_to_key(func)

functools.cmp_to_key(func) 用于将旧式比较函数转换为键函数。它在 Python 2.7、Python 3.2 及更高版本中可用。

根据 Python 3 文档 ,“比较函数是任何可调用函数,它接受两个参数,对它们进行比较,如果小于则返回负数,如果相等则返回零,如果大于则返回正数。函数 key 是可调用函数,它接受一个参数并返回另一个值以用于排序 key 。”

在 Python 2.4 之前,没有 sorted() , list.sort() 也不接受关键字参数。相反,Python 2 支持一个 cmp 参数来处理用户指定的比较函数。

当将代码从 Python 2 移植到 Python 3 时,您可能需要将函数从 转换 cmp key 。在 Python 3 中, functools.cmp_to_key(func) 引入了 以简化该过程。

我们将使用 functools.cmp_to_key(func) 接受关键函数(例如 s或 )ted() or itertools.groupby() ,我在之前的文章中讨论过这些函数。使用我们之前的示例按立方值对数字进行排序,您可以编写自定义 cmp 函数,如下所示:

>>> import functools

>>> l = [6, 8, 10, 23, -4, -7]

>>> def compare(x, y):
...    return x ** 3 - y ** 3

>>> sorted_l = sorted(l, key=functools.cmp_to_key(compare))
>>> print(sorted_l)
[-7, -4, 6, 8, 10, 23]

有时,使用 key 可能不如 明显 cmp 。在这种情况下,使用 可能更好 functools.cmp_to_key(func) ,因为它更具可读性和直观性。

例如,在去年的 matura (类似于 A Levels、Abitur 或 Baccalauréat 的波兰考试)中,可选的 IT 部分有一项练习,其中包括:

满足 以下 对 (number1, word1) 小于 对 (number2, word2)

  • 数字 1 < 数字 2

或者:

  • number1 == number2 并且 word1 按字母顺序小于 word2 .

例如, 对 (1, bbbb) 小于 对 (2, aaa) ,但 对 (3, aaa) 小于对 (3, ab) .

换句话说,我们希望该对按第一个元素和第二个元素的升序排序。

因此,我们期望按以下顺序返回这些对: (1,bbbb),(2,aaa),(3,aaa),(3,ab)。

下面是 cmp 解决此问题的自定义函数:

from functools import cmp_to_key

def compare(pair1, pair2):
	number1, word1 = pair1
	number2, word2 = pair2
	if number1 == number2:
		if word1 < word2:
			return -1
		else:
			return 1
	if number1 < number2:
		return -1
	else:
		return 1

compare_key = cmp_to_key(compare)

通过对元组列表进行排序 key 来解决问题

>>> # List of tuples
>>> l = [(3, 'aaa'), (1, 'bbbb'), (3, 'ab'), (2, 'aaa')]

>>> # Sort with key on first and second element of each tuple
>>> sorted(l, key = lambda x: (x[0], x[1])) 
[(1, 'bbbb'), (2, 'aaa'), (3, 'aaa'), (3, 'ab')]

我们还可以尝试通过按降序对第一个元素进行排序,按升序对第二个元素进行排序,使问题更具挑战性。同样,我们可以用以下方法解决它 key

>>> # Sort number in descending order and word in ascending order
>>> sorted(l, key = lambda x: (-x[0], x[1]))
[(3, 'aaa'), (3, 'ab'), (2, 'aaa'), (1, 'bbbb')]

假设我们把问题反过来,第一个元素按升序排列,第二个元素按降序排列。在这种情况下,传递参数 reverse as True 就可以解决问题。

>>> # Sort number in ascending order and word in descending order
>>> sorted(l, key = lambda x: (-x[0], x[1]), reverse=True)
[(1, 'bbbb'), (2, 'aaa'), (3, 'ab'), (3, 'aaa')]

很难找到 cmp 不能被 替代的 key 。由于性能方面 functools.cmp_to_key(func) 与 相比非常慢 key ,因此它只能作为在 Python 中实现自定义排序函数的最后手段。

如果您想了解有关映射函数的更多信息,请查看我关于 filter()、map() 和 reduce() .

关于 Python 中自定义排序函数的总结

在本文中,我们探讨了如何在 Python 中实现自定义排序和比较函数。我们了解了一些 Python 历史,并尝试了解 cmp 在 Python 2 和 3 之间使用和键做出的选择,以便在 Python 中实现自定义排序函数。

为了更好地理解这些文章中解释的概念,使用代码片段并构建自己的示例总是一个好主意。

最后,如果你想了解有关 Python 中数据操作的更多信息,请随时查看 Yigit 的精彩文章,了解 如何使用 Pandas 数据框中 .

如果您想更上一层楼,请尝试我们的 Python 数据科学课程 。祝您学习愉快!

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部
1.093092s