刚开始学习的那个时候, 一旦手里拿到了一串数据, 我的条件反射便是去写一个for循环, 并且在这个for循环里面还需要加上几个if语句, 吭哧吭哧地写上十几行代码才能够把活给干完。后来才了解到, 其实早就在内置函数里给我们准备好了“数据处理四件套”——map、、、。同样的一个需求, 可是别人仅仅用两行代码就能够搞定, 而我写了二十行代码, 纯粹属于费力不不讨好、毫无成效却又毫无益处地做了这件事。
今儿就把这四件套一回讲明白。你只需记着一个景象: 把数据设想成流水生产线上的一批货物, 四个函数便是四个各异的“车间”。
第一个车间:map,批量加工厂
map所做之事极为纯粹, 针对一组数据当中的每一个单独元素, 进行共同且一致的同一道加工处理, 随后吐露出一组崭新的数据。最为奇妙的是, 它仅仅操作“出厂件”, 绝不触碰你的“原件”。
nums = [10, 20, 30, 40] result = list(map(lambda x: x * 2, nums)) print(result) # [20, 40, 60, 80] print(nums) # [10, 20, 30, 40] 原件一点没变这儿, x 乘以 2 的这种情况便是那道所谓的“加工工序” , map 会将 nums 里面的每一个数, 逐个送去进行这道工序, 10 会变为 20, 20 会变为 40 , 按这样的方式依次变化, 最终整工整齐地交还给你一组全新的数。
两个坑新手必踩:
1. 返回, map生成而是为并非列表所谓迭代器样式之物。直接以print实施操作之时将目睹莫名内存地址呈现情况出现。若愿望查看其中内容, 需记得运用list()进行包裹处理, 或者规规矩矩借助for循环予以遍历方可达成目的。
2. 迭代器十分“娇气”, 一旦遍历(或者进行 list 转换)一回便会用完, 当第二次再进行转换时就会成为空列表。因而要么尽早运用 list() 将结果存入变量, 要么从一开始直接采用 list(map(...)) 一步达成。
第二个车间:,质检筛子
承担“挑货”职责: 把一组数据当中合乎条件的筛选找出来, 将不符合心意的舍弃掉。
最经典的例子,从一堆人里挑出成年人:
persons = [ {"name": "张三", "age": 15}, {"name": "李四", "age": 16}, {"name": "王五", "age": 17}, {"name": "李华", "age": 18}, {"name": "赵六", "age": 19}, {"name": "孙七", "age": 20}, ] adults = list(filter(lambda p: p["age"] >= 18, persons)) print(adults) # 只剩李华、赵六、孙七留意, 所书写的是p >= 18, 并非p >= 18。p乃是整本“人事档案”(字典), 你需要先掀翻档案拿出age这一栏而后再去比较大小, 径直拿整本字典比较必定会报错。
另外存在一个偷懒的神奇技巧, 当第一个参数直接传递None时, 它能够自动将“假值”全部筛选掉。
data = [0, 1, '', 'Hello', [], (), 5] print(list(filter(None, data))) # [1, 'Hello', 5]0、空着的字符串, 空着的列表, 空着的元组, 转变成布尔值的时候, 都是呈现为False, 会自动被舍弃掉;其余的那些具有真值的内容, 全部都留存下来。在清理不干净的数据时, 运用这样的办法, 会格外让人觉得畅快。
map以及它和都返回迭代器, 它俩都存在着可能“使用一次就会被耗尽”这种情况;而它们之间的区别在于——map不会改变元素数量然而, 却有可能会把数量筛选少。记住这单独的一个要点, 能够减少半小时的调试时间。
第三个车间:,重新排队
负责进行排序 并且 它跟前面的那两个存在差异 直接返回的是一个列表 不需要你再次通过list()进行转换 拿到之后就能够直接使用。
names = ['python', 'go', 'java'] print(sorted(names, key=len)) # ['go', 'java', 'python'] print(sorted(names, key=len, reverse=True)) # ['python', 'java', 'go']按字符编码进行的默认排序, 是这样排的(由于此原因, 'go' 处于最前面), 然而当添加了 key=len 后, 就转变为按照"字符串长度"来进行排序。参数 key 所具备的能力, 便是能够让你去指定"按照何种方式进行排序"。
排序字典列表也靠它。比如按年龄给一群人排队:
print(sorted(persons, key=lambda p: p["age"])) # 想要从大到小?加个 reverse=True 就行特意提及两位亲戚, max以及min同样能够运用key, 想要寻觅年龄处于最大状态或者最小状态的那个人。
print(max(persons, key=lambda p: p["age"])) # 李华(20岁) print(min(persons, key=lambda p: p["age"])) # 张三(15岁)单独的一句话, 一旦是涉及到了"比大小、挑极值、排顺序"这些方面, 那么首先就要去想 / max / min 以及加上 key。
第四个车间:,打包机
之前的三个均是“一对多”或者“多对多”这种情况, 与之相反采取这样的做法——把那一堆的数据如同滚雪球一般进行合并, 最终形成一个结果。在生活当中它就类似于把那些散装的零件逐个放进同一个箱子里面, 最后仅仅交给你一个箱子。
它比较特殊,不能直接用,得先从 模块请过来:
from functools import reduce nums = [1, 2, 3, 4, 5] total = reduce(lambda a, b: a + b, nums) print(total) # 15它这样运行, 逻辑是, 首先抓取前面的两个数, 也就是1和2, 将它们相加而得到3, 接着要把3跟下一个数3相加从而得到6, 之后6再加上4得出10, 然后10加上5得到15。每一回的“和”都会转变成为下一轮的a, 新进来的元素当作b, 一直到队伍全部走完。
你还能传第三个参数当"初始值":
print(reduce(lambda a, b: a + b, nums, 10)) # 25这回搞的头一遭计算的是十加上一, 这等同于预先朝着箱子里头放置了一件垫底的货物。
若进行换行操作, 便可将加号修改成乘号, 随即就会变成求乘积的情况;要是将数字替换为字符串, 那就会成为拼接的情形。
words = ['ab', 'cd', 'ef'] print(reduce(lambda a, b: a + b, words)) # 'abcdef'记好了, 给你交予的那个合并函数, 始终都仅仅能够收纳两个参数(a以及b), 再多写上哪怕一个, 也不会有人给你去传递的, 直接就会出现报错情况。千万别存有贪心的想法哟。
四件套合体,记住这张表
回头看,它们其实对应了数据处理的四种本能动作:
• 要统一加工 → map
• 要挑三拣四 →
• 要排排坐 →
• 要合并汇总 →
又一次拿到那一堆杂乱无章的数据时, 先别急着去写for循环。在心里先过一遍, 我究竟是要进行加工, 还是要进行筛选, 亦或是要进行排序, 又或者是要进行合并呢? 指向对准车间, 将数据送进去, 代码变短了, 思路也变得清爽了。
与“返回的‘迭代器’”相关联的“map”究竟是什么东西? 为何那“用一次就没了”呢? 下一篇咱们专门去拆解它。要是觉得有用那就先点个赞收藏起来, 等用到的时候把其翻找出来便可以了。