如何优雅获取Python中max/min函数对应的key值?
解决非确定性key下同时获取max/min值与对应key的问题
如果你在用Python的max()或min()时遇到了非确定性key函数的场景,肯定会发现常规方法根本行不通——毕竟重复调用key函数会得到不一样的结果,没法准确拿到对应的值和key。
先说说为什么常规方案不行:
- 直接用
max_val = max(iterable, key=key)再max_key = key(max_val):因为key是非确定性的(比如带随机数的函数),两次调用key的结果可能完全不同,对应关系直接出错。 - 用
sorted(iterable, key=key)[0]再算key:本质和上面一样,排序时计算的key和后续调用的key结果不一致,完全没法保证对应性。
那怎么优雅解决这个问题?这里有个兼顾惰性求值、适配任意可迭代对象,还和原生max行为保持一致的自定义函数:
from itertools import tee def max_and_key(iterable, *, key): i1, i2 = tee(iterable) max_val = max((k, -i, v) for i, (k, v) in enumerate(zip(map(key, i1), i2))) return max_val[2], max_val[0]
来拆解下这个函数的设计细节:
tee(iterable):把输入的可迭代对象拆成两个独立但同步的迭代器i1和i2,这样我们可以同时遍历元素和它对应的key,不会因为迭代器提前耗尽出问题。zip(map(key, i1), i2):一边用map(key, i1)计算每个元素的key,一边用i2取原元素,zip保证两者严格一一对应,而且是惰性处理的——不会一次性把所有元素和key都加载到内存里,对大迭代器非常友好。enumerate(...)+(k, -i, v):当多个元素的key值相同时,原生max会返回第一个出现的元素,这里用-i(i是元素的索引)来保证排序稳定性:当k相同时,-i越大(也就是i越小,元素出现越早),整个元组的优先级越高,max就会选中最早出现的那个元素,和原生函数行为完全一致。
调用的时候也很直观,比如拿一个带随机偏移的非确定性key举例:
import random def random_key(x): return x + random.random() my_list = [1, 2, 3] val, k = max_and_key(my_list, key=random_key) print(f"最大值: {val}, 对应key: {k}")
这样就能保证拿到的val和k是完全对应的,不会因为重复调用key函数出现不一致的问题。
内容的提问来源于stack exchange,提问作者Mad Physicist
相关产品推荐
相关产品推荐

