Python Max/Min函数中的iter和key参数是如何工作的?

5

我是一个对Python比较新的人,一直在阅读各种内置函数的文档。

谈到max/min函数:

 `max(arg1, arg2, *args[, key])`  or `max(iterable[, key])`

我知道arg1,arg2等或可迭代对象可以是一组随机的值,但是“key”元素的作用是什么?有人能给我一个应用它的例子吗?

通常当我看到这个内置函数时,我会自动想象一个随机列表,比如x = [1,2,3],然后max(x)将返回值3。但是,“key”功能除了遍历一个简单直接的列表之外,还能提供什么方式来操作该函数呢?

我是Python初学者,对Python文档中的所有术语都不太熟悉。

谢谢, Ed


2
你读过例如 https://dev59.com/LmMl5IYBdhLWcg3wkXtx 这个链接吗? - jonrsharpe
4个回答

5

关键是使用自定义比较函数进行传递。

例如:按列表长度输出 max,其中 arg1、arg2 都是列表。

>>> max([1,2,3,4], [3,4,5], key=len)
[1, 2, 3, 4]

示例:输出 args 列表元素之和最大的列表

>>> max([1,2,3,4,5], [3,4,5], key=sum)
[1, 2, 3, 4, 5]

>>> max([1,2,3,4], [3,4,5], key=sum)
[3, 4, 5]

你可以使用特定的比较函数来比较不同的参数对象。


我可以在关键元素中使用布尔值吗? - user40720
@user40720 你能具体说明一下吗?按照定义,布尔类型只有两个值,True或False,所以我不确定你想要如何“融合”它们。 - Anshul Goyal
如果您的问题得到解决,请不要忘记接受并点赞 :) - Anshul Goyal

3

当你想要查找序列的最大值并且想要一个特定的最大值定义时,你可以使用它。

例如,假设我有一个tuple列表。如果我只是使用max而没有key参数,它将默认使用每个元组中的第一项。

>>> l = [(1,3), (2,4), (1,9), (4,1)]

>>> max(l)
(4, 1)

但是,如果我想从列表中获取最大值,但要考虑元组的第二个元素呢?

>>> max(l, key = lambda i : i[1])
(1, 9)

# Or

>>> import operator
>>> max(l, key = operator.itemgetter(1))
(1, 9)

如果有一个字符串列表,你想要按照数字值找到最大值,该怎么办?

>>> l = ['4', '11', '6', '31']

只使用max将使它们按字典顺序排序

>>> max(l)
'6'

但是我还可以使用 key

>>> max(l, key = lambda i: int(i))
'31'

提到 operator 真是太好了!最后一个例子也可以简化为 max(l, key=int)。避免使用 lambda,它们速度慢且难以调试。 - uranusjr

1
>>> my_list = ["cat","dog","monkey","elephant","horse"]
>>> max(my_list,key=len)
'elephant'

这里会检查哪个元素有最大的长度。 在这里,key定义了根据什么参数进行比较,max将选择最大值。

key可以是任何内置函数或用户定义的函数。


1
考虑有一个像这样定义的对象列表:
class MyItem:
    def __init__(self):
        self.count = 0

    def increase(self):
        self.count += 1

    def decrease(self):
        self.count -=1

    def get_count(self):
        return self.count

all_objects = []
for i in range(10):
    all_objects.append(MyItem())

在程序的各个部分,会调用increasedecrease方法。现在你想找到计数最多的项,但max函数并不知道对象实现的细节。因此,你需要让它知道使用哪个函数来评估它们之间的项。在这种情况下,这将是项的get_count方法,你可以像这样调用max

max(all_objects, key=lambda x: x.get_count)

基本上,一个“键”是排序的“推理器”,是用于比较的值。
为了更好地理解它,请考虑每次调用像这样的整数列表:
some_list = [1,2,3]
max(some_list)  # returns 3

将其作为未修改值提供密钥与提供其作为键相同:

some_list = [1,2,3]
max(some_list, key=lambda x:x)

更新

作者问道:

我可以将布尔值合并到键元素中吗?

因此,我正在扩展我的答案以回复。
简而言之,答案是:可以。但在实践中,这几乎没有任何用处。至于解释,请考虑以下情况:

my_list = [True, False, False, True, False, False, False]
max(my_list)

结果显然是True,因为约定True > False。但问题是,返回哪个True对象(请记住,Python中的everything都是对象,即使是布尔类型也是如此)?是第一个还是第二个?这取决于max的内部实现方式。由于这一点,我们没有这个应用的实际用途。(顺便说一句,max被实现为返回第一个,但这在这个时候并不关系我们。)

重要提示:上面的示例是一个简化版,假设两个True对象实际上是两个不同的对象,这是不正确的。在Python中,它们实际上是相同的对象,正如评论中@mu無所指出的那样。将其视为一个粗略的示例,有关更相关的示例,请继续阅读。

但让我们来看看这在我们之前的示例中的行为:

class MyItem:
    def __init__(self, id):
        self.count = 0
        self._bool = bool(random.randrange(2))
        self.id = id

    def increase(self):
        self.count += 1

    def decrease(self):
        self.count -=1

    def get_count(self):
        return self.count

    def get_bool(self):
        return self._bool

我们只添加了三个东西,一个用于识别对象的 id,一个私有属性 _bool 和一个 getter 函数 get_bool 作为 key 使用。让我们创建一个这样的对象列表并进行一些随机增量以区分它们:
import random
all_objects = []
for i in range(10):
    new_obj = MyItem(i)
    for k in range(random.randrange(10)):
        new_obj.increase()
    all_objects.append(new_obj)

此时,我们有一个名为 all_objects 的列表,其中包含10个具有随机值的 MyItem 对象,在它们的 count 属性中以及一个随机的 boolean 值在它们的 _bool 属性中。
现在让我们看看当我们尝试对其进行排序时会发生什么。首先,我们将打印出所有这些对象,这样更容易得出结论。我将显示三个连续的结果作为列以保留空间。
# a helper function to print formatted output  
def print_object(obj):
    print "id: {0} count: {1} _bool: {2}".format(o.id, o.get_count(), o.get_bool())

# print all objects followed by delimited line
# for the object returned by max
for o in all_objects: print_object(o)
print "-"*27
max_obj = max(all_objects, key=lambda x:x.get_bool())
print_object(max_obj)

输出:

id: 0 count: 1 _bool: False     id: 0 count: 2 _bool: False     id: 0 count: 1 _bool: False
id: 1 count: 7 _bool: True      id: 1 count: 3 _bool: False     id: 1 count: 4 _bool: False
id: 2 count: 0 _bool: False     id: 2 count: 1 _bool: False     id: 2 count: 2 _bool: False    
id: 3 count: 5 _bool: False     id: 3 count: 4 _bool: False     id: 3 count: 1 _bool: True
id: 4 count: 4 _bool: False     id: 4 count: 6 _bool: False     id: 4 count: 9 _bool: False
id: 5 count: 4 _bool: False     id: 5 count: 6 _bool: False     id: 5 count: 3 _bool: False
id: 6 count: 7 _bool: True      id: 6 count: 4 _bool: False     id: 6 count: 5 _bool: False
id: 7 count: 8 _bool: True      id: 7 count: 7 _bool: True      id: 7 count: 1 _bool: True
id: 8 count: 1 _bool: True      id: 8 count: 8 _bool: False     id: 8 count: 9 _bool: False
id: 9 count: 7 _bool: True      id: 9 count: 4 _bool: False     id: 9 count: 1 _bool: False
---------------------------     ---------------------------     ---------------------------
id: 1 count: 7 _bool: True      id: 7 count: 7 _bool: True      id: 3 count: 1 _bool: True

从输出结果中,我们可以清晰地看到该函数返回了第一个带有_bool属性且值为True的项目。这几乎不是任何重要事物的max值...

我能把布尔值加入关键元素中吗? - user40720
可以,但是这样做没有太多用处。我会在我的回答中更新详细信息。 - bosnjak
但问题是,返回哪个True对象是错误的,所有的True都是相同的True对象。在你的shell中运行这个命令:l = [True, True]; id(id(l[0]) == id(l[1])) == id(l[0]) == id(l[1]) - Anshul Goyal
@mu無:好的,说得好。我忽略了这个事实,我被我提供的实际示例所引导,使用了自定义对象,因此我忽略了实际测试。我会相应地编辑我的答案。谢谢! - bosnjak

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