嵌套列表中的min/max函数是如何工作的?

27

假设有一个嵌套列表:

my_list = [[1, 2, 21], [1, 3], [1, 2]]

当对此进行min()函数调用时:

min(my_list)

收到的输出是

[1, 2]

为什么它能起作用?它是如何起作用的?有哪些使用案例呢?

4个回答

42

Python中如何比较列表和其他序列?

在Python中,列表(以及其他序列)是按词典顺序进行比较的,而不是基于任何其他参数。

序列对象可以与具有相同序列类型的其他对象进行比较。比较使用词典排序:首先比较前两个项目,如果它们不同,则确定比较结果;如果它们相等,则比较下两个项目,依此类推,直到任一序列用尽为止。


什么是词典排序?

来自维基百科关于词典排序的页面

词典顺序(也称为字典顺序、字典序、字母表顺序或词典积)是一种将单词按字母顺序排列的方式的泛化。

min函数返回可迭代对象中最小的值。因此,列表[1,2]的词典值是该列表中最小的。您可以使用[1,2,21]进行检查。

>>> my_list=[[1,2,21],[1,3],[1,2]]
>>> min(my_list)
[1, 2]

这个min函数的用法是什么?

对于my_list中的每个元素,首先比较[1,2,21][1,3]。现在根据文档:

如果要比较的两个项目本身是相同类型的序列,则进行递归的词典式比较。

因此,[1,1,21]的值小于[1,3],因为[1,3]的第二个元素是字典上更高的值,而[1,1,21]的第二个元素是1

现在比较[1,2][1,2,21],并从文档中添加另一个参考信息:

如果一个序列是另一个序列的初始子序列,则较短的序列更小[1,2][1,2,21] 的初始子序列。因此,[1,2] 在整体上比[1,2,21]更小。 因此,[1,2] 被作为输出返回。可以通过使用 sorted 函数验证这一点。
>>> sorted(my_list)
[[1, 2], [1, 2, 21], [1, 3]]

如果列表有多个最小元素怎么办?

如果列表包含重复的最小元素,则返回第一个

>>> my_list=[[1,2],[1,2]]
>>> min(my_list)
[1, 2]

这可以通过调用 id 函数进行确认

>>> my_list=[[1,2],[1,2]]
>>> [id(i) for i in my_list]
[140297364849368, 140297364850160]
>>> id(min(my_list))
140297364849368

如何防止在min中进行词典比较?

如果所需的比较不是词典比较,则可以使用key参数(如Padraic所述)。

min函数有一个附加的可选参数,名为keykey参数需要一个函数。

可选参数key指定一个一元排序函数,类似于list.sort()中使用的函数。如果提供了key参数,则必须以关键字形式提供(例如,min(a,b,c,key=func))。

例如,如果我们需要通过长度获取最小的元素,则需要使用len函数。

>>> my_list=[[1,2,21],[1,3],[1,2]]
>>> min(my_list,key=len)            # Notice the key argument
[1, 3]

我们可以看到这里返回了第一个最短的元素。

如果列表是异构的怎么办?

在 Python2 之前

如果列表是异构的,则会考虑类型名称进行排序,请查看比较,

除数字外,不同类型的对象按其类型名称排序

因此,如果您在那里放置一个int和一个list,则将获得整数值作为最小值,因为i的值低于l。类似地,'1'的值将高于这两个值。

>>> my_list=[[1,1,21],1,'1']
>>> min(my_list)
1

Python3及以后版本

然而,这种令人困惑的技术在Python3中被移除了。它现在会引发一个TypeError异常。阅读Python 3.0中的新特性

当操作数没有有意义的自然排序时,比较运算符(<<=>=>)引发一个TypeError异常。因此,像1 < ''0 > Nonelen <= len这样的表达式不再有效,例如None < None引发TypeError而不是返回False。其推论是,对异构列表进行排序不再有意义 - 所有元素必须相互可比较

>>> my_list=[[1,1,21],1,'1']
>>> min(my_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < list()

但它适用于“可比类型”,例如。
>>> my_list=[1,2.0]
>>> min(my_list)
1

我们可以看到这里的list包含了floatint类型的值。但是由于floatint是可比较的类型,所以min函数在这种情况下也能正常工作。


1
是的,这些解释正是我想要的,不知道这是否是 OP 想要的。 - Remi Guan
2
是的,我也很满意,但有人能想出一些用例吗?我想不出来。我的意思是,一个列表比另一个列表小,这真的有意义吗?Python是否有意支持它,还是它是实现的结果? - Ahsanul Haque
2
@AhsanulHaque 我使用的其中一个用例是基于索引(在我的情况下恰好是第一个元素)对嵌套列表进行排序。这些列表是使用 csv 模块获取的。据我所知,这可能是有意为之,但我还不能确认。我会进行研究并让您知道。 - Bhargav Rao
对于 Python2 特定的!!! 需要注意:如果你在使用 Python 3,则会引发 TypeError: unorderable types: int() < list() - Remi Guan
3
是的。在Python 3中,他们取消了混合类型比较。请参见Python 3.0的新功能 - Bhargav Rao
2
你也可以传递一个关键字给min函数,例如 min(my_list, key=len),它将返回最短的列表。 - Padraic Cunningham

5

词典排序的一个简单应用是用于创建可排序的namedtuple类。

from collections import namedtuple
Time = namedtuple('Time', ['hours', 'minutes', 'seconds'])

t1 = Time(hours=8, minutes=15, seconds=30)
t2 = Time(hours=8, minutes=15, seconds=0)
t3 = Time(hours=8, minutes=30, seconds=30)
t4 = Time(hours=7, minutes=15, seconds=30)

assert min(t1, t2, t3, t4) == t4
assert max(t1, t2, t3, t4) == t3

2

逐个元素比较两个列表

即使两个列表的大小不同,也会从第一个元素开始逐个元素进行比较。

现在假设已经检查了列表的每个元素,并且它们都相同,在较短的列表中没有下一个元素。然后,较短的列表被声明为比较长的列表小。

示例:

>>> [1,2]<[1,3]
True
>>> [1,2]<[1,2,21]
True
>>> [1,3]<[1,2,21]
False
>>>[1,2,22]<[1,2,21]
False
>>>[1]<[1,2,21]
True
>>>

1
它逐个比较列表的元素:
>>> [1,2]<[1,3]
True
>>> [1,2]<[1,2,21]
True
>>> 

2
这真的回答了OP的问题吗?我认为OP知道,但是为什么和如何呢?澄清一下我的评论:Python如何比较两个列表?为什么[1,2] < [1,3]等于True - Remi Guan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接