基础篇_010_函数_max()和min()函数

  

----简单的引入 ===》

  print(max(1, 2, 3, 4, 5))的输出结果肯定是5,"就讲这玩意儿?这换我奶奶都会好伐",你的内心一定对此嗤之以鼻。都说了使简单的引入嘛,要真就这么一点,我疯了单独拿出来,敲字儿不累的哈。来来来,你要的重量级骚操作来了。

 

----高级玩法 ===》

  在说到这个骚操作之前,先来看一下之前说的"zip()函数"。OK,我们来接着研究这操作是怎么个高级法。

  1. 先不说高级的,现在有一个需求: "在一个列表中挑选出最大的值,my_list = ['simba', 'alex', 'vivian']",这个比较简单 ===》

my_list = ['simba', 'alex', 'vivian']
print(max(my_list))     # 输出:vivian

  2. 好的,大家应该都差不多知道了下面该发生啥事了叭?没错,给咱们的需要又变了(没事的,已经习惯了): "在my_list = [("simba", 18), ("vivian", 19), ("peiqilaoshi", 30)]"中找出最大的。咋一看比较懵逼,但一想,决定凑个运气试一试直接max(my_list) ===》

1 my_list = [("simba" ,18), ("vivian", 19), ("peiqilaoshi", 30)]
2 print(max(my_list))     # 输出:('vivian', 19)
3 # 诶,可以得出结果,我们反过来看看
4 my_list = [(18, "simba" ), (19, "vivian"), (30, "peiqilaoshi")]
5 print(max(my_list))     # 输出:(30, 'peiqilaoshi')
6 # 好像有点感觉了,看看比较一下字符串
7 print(max("abcd5553"))     # 输出:d
8 # なるほど、真実はいつも一つ

说了这么多,其实就只是向引出一点,max()函数比较的规则是: 如果参数不是可迭代的序列,那就比较它本身;如果是可迭代序列,就将序列中的元素依次取出比较。而且只能是相同类型之间进行比较,传入两个不同数据类型的参数是pycharm直接报错。

  3. 费劲"千辛万苦"理解到这一点后,我们正式进入正片。正片当然就要有正片儿的需求:"把这字典中年纪最大的内个'千年王八万年龟'找出来,age_dict = {"simba_age": 18, "vivian_age": 19, "haifenglaoshi": 10000}"。懵了,这咋办啊? ===》

 1 age_dict = {"simba_age": 18, "vivian_age": 19, "haifenglaoshi": 10000}
 2 # 首先要获取年龄的最大值
 3 print("age_max", max(age_dict.values()))    # 输出:age_max 10000
 4 # 但是这还不够,还不知道人是谁,所以不能将key和value分开,想到刚刚学的zip()函数,这里有一个细节需要注意:
 5 # 由于max比较大小的时候是从前向后依次比较,而我们需要的是年龄,所以要将年龄放在名字前面
 6 my_zip = zip(age_dict.values(), age_dict.keys())
 7 # # 我们来查看一下my_zip中的元素是什么
 8 # for item in my_zip:
 9 #     print(item)
10 # # (18, 'simba_age')
11 # # (19, 'vivian_age')
12 # # (10000, 'haifenglaoshi')
13 # 上面必须注释掉,因为zip的返回值是一个迭代器,只能迭代一次
14 # my_zip中是3个元组,此时我们便可以通过比较这三个元组大小来获取年龄最大的那个人
15 # 由于zip()函数的返回值是一个<zip object at 0x000001AFF6649848>,不是一个可以比较序列,必须将它"可迭代化"
16 result_list = list(my_zip)
17 # 比较
18 result = max(result_list)[1]
19 print(result)       # 输出:haifenglaoshi

所以,用一句话总结: print(max(zip(my_dict.values(), my_dict.keys()))[1])  # 输出:haifenglaoshi

鲁迅先生说过什么来着: 总有一些人打着魔术的旗号,在光天化日之下施展魔术!

  4. 总有些人喜欢异想天开,想尝试一下"邪教",问: "字典可不可以比较"。行,成全你们 ===》

其实这句话有一丁点儿歧义: 到底是"字典可不可以作为参数传入max()函数" 还是 "字典可不可以比较大小",我们就分别来看一下哈 ===》

--(1). 字典可不可以作为参数传入max()函数: 答案是肯定的 ===》

age_dict = {
    "simba_age": 18,
    "vivian_age": 19,
    "haifenglaoshi": 10000
}
print(max(age_dict))    # 输出:vivian_age
# 传入字典默认的方式是传入key值,当然也可以传入value值
print(max(age_dict.values()))   # 输出:10000

--(2). 字典可不可以比较大小: 答案是否定的 ===》

my_list_dict = [
    {"name": "simba", "age": 18},
    {"name": "peiqilaoshi", "age": 20},
    {"name": "haifenglaoshi", "age": 19}
]
print(max(my_list_dict)) # 报错:'>' not supported between instances of 'dict' and 'dict'
# 字典之间无法比较大小,这是因为字典是无序的,无法从第一个位置开始比较

  5. 那既然无序的数据类型不可以,那按道理说set集合它也是无序的,为森膜它就可以呢?===》

 1 my_list_set = [
 2     {1, 2, 3, 4},
 3     {2, 3, 4, 5},
 4     {3, 4, 5, 6}
 5 ]
 6 print(max(my_list_set)) # 输出:{1, 2, 3, 4}——第一行
 7 # ???按道理应该也是输出第三个啊,何况set集合数据类型是无序的!
 8 # 既然max()函数可以正常运行,那证明set可以使用关系运算符比较大小
 9 print("{1, 2, 3, 4} >  {2, 3, 4, 5}", ({1, 2, 3, 4} > {2, 3, 4, 5}))
10 # 输出:{1, 2, 3, 4} > { 2, 3, 4, 5}     False
11 print("{1, 2, 3, 4} == {2, 3, 4, 5}", ({1, 2, 3, 4} > {2, 3, 4, 5}))
12 # 输出:{1, 2, 3, 4} == {2, 3, 4, 5}     False
13 print("{1, 2, 3, 4} <  {2, 3, 4, 5}", ({1, 2, 3, 4} > {2, 3, 4, 5}))
14 # 输出:{1, 2, 3, 4} == {2, 3, 4, 5}     False
15 # 卧槽,这是什么神仙情况,当我三岁小孩儿嘛?我们换一下顺序,将第一行和第三行交换
16 my_list_set = [
17     {3, 4, 5, 6},
18     {2, 3, 4, 5},
19     {1, 2, 3, 4}
20 ]
21 print(max(my_list_set)) # 输出:{3, 4, 5, 6}——第一行

看到这里, 我们貌似发现了一个带定理: 如果是max()中处理的比较对象是集合的话返回第一行。

emm...我感觉自己都不信了,若真是这样...那Python生命周期也就快到了叭。好了,不说废话了,步入正轨,在set集合中我们是不是学了很多关于关系运算的运算方法啊?这里当然也就适用了啊!set中的比较大小是用来比较父子集合关系的,因为上面{1, 2, 3, 4}和{2, 3, 4, 5}这两个集合谁都不是谁的子集、而且两个集合也不同,所以才出现了三种运算的结果都是False的情况。

print("{1, 2, 3, 4} <  {1, 2, 3, 4, 5}", ({1, 2, 3, 4} < {1, 2, 3, 4, 5}))
# 输出:{1, 2, 3, 4} <  {1, 2, 3, 4, 5}    True
print("{1, 2, 3, 4} == {1, 2, 3, 4}", ({1, 2, 3, 4} == {1, 2, 3, 4}))
# 输出:{1, 2, 3, 4} == {1, 2, 3, 4}       True
print("{1, 2, 3, 4} >  {1, 2, 3, 4, 5}", ({1, 2, 3, 4} > {1, 2, 3, 4, 5}))
# 输出:{1, 2, 3, 4} >  {1, 2, 3, 4, 5}    False

说到这里,我突然想研究一下max()函数到底是怎么运作的,因为刚才即使三个运算操作都是返回的False,但还是返回了一个值,而且巧的是都是第一个,这让我不禁想到了一个叫做"直接选择法"的算法。直接选择法是个什么玩意儿呢?他就像字面上说的一样,直接选择一个最值

# 直接选择法:
def find_max(arg):
    max_index = 0
    for index in range(1, len(arg)):
        if arg[max_index] < arg[index]:
            max_index = index
    return arg[max_index]
print(find_max((2, 3, 4, 5)))   # 输出:5

  6. 额...感觉废话说得有点儿多哈,下面开始真正的见证奇迹的时刻(是真的,绝逼真的)。"终极玩法Show Time!" ===》

  有些细心的朋友发现了,在使用max()方法的时候,后面还有一个关键字参数: key。那么这个key是干嘛用的呢?Python给出的解释为:  key = func,这是什么意思?看得小脸一懵。但仔细想一想,可能表示这个key的类型为函数名,再回忆一波map()、filter()、reduce()函数,发现都有一个参数名字叫做func,なるほど、真実はいつも一つ。这个key的官方解释其实是要查看Python文档的,在文档中的解释为:he。

所以总的来说,key就是和那三个函数一样,传入一个函数作为传入序列每一个元素处理的方法,然后再返回最大值。这样我们回头再看第4点的第(2)小点,便可以通过传入一个匿名函数来获取字典的value值,然后让max()函数最终执行的是value,那么字典也就能用了 ===》

my_list_dict = [
    {"name": "simba", "age": 18},
    {"name": "peiqilaoshi", "age": 20},
    {"name": "haifenglaoshi", "age": 19}
]
print(max(my_list_dict, key=lambda my_dict:my_dict["age"]))
# 输出:{'name': 'peiqilaoshi', 'age': 20}
# 这句话相当于执行了这样一条操作: result = [] for item in my_list_dict: result.append(item["age"]) max_age = max(result) for item in my_list_dict: if item["age"] == max_age: print(item)
# 输出:{'name': 'peiqilaoshi', 'age': 20}

 

----写在最后,总结 ===》

  1. 首先你传入的参数必须要能够用关系运算符比较大小,如果不行,就必须在后面传入关键字参数key来指定方法。

  2. max()函数的比较规则是: 

--(1). 相当于一个for循环取出每一个元素进行对比。注意:不同类型之间的元素不能进行比较。

--(2). 每一个元素进行比较,是从每个元素的第一个位置依次比较,如果这一个位置分出了大小,后面的就都忽略了。

  3. max()函数用的算法猜测是用的"直接选择法",毕竟真的太像了。

 

 

 

posted @ 2020-02-23 22:26  BNTU  阅读(668)  评论(0)    收藏  举报