Python数据处理四件套:告别冗长循环
初学习之阶段, 一旦手中获取到一众数据, 我的一种条件反射乃是撰写一个 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 变为 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, keylen)) # [go, java, python] print(sorted(names, keylen, reverseTrue)) # [python, java, go]默认排序, 是依字符, 按其编码来进行排列的, 所以, ‘go’会排在最前面, 然而, 一旦添加了keylen , 那么排序方式就被改成了按照字符串长度进行排列, key这个参数所具备的能力, 便是能够让你去指定按照什么来进行排列。排序字典列表也靠它。比如按年龄给一群人排队print(sorted(persons, keylambda p: p[age])) # 想要从大到小加个 reverseTrue 就行顺带提及一下两个亲属, max以及min同样能够运用key。要寻觅年纪最为大的那个人, 要寻觅年纪最为小的那个人。print(max(persons, keylambda p: p[age])) # 李华20岁 print(min(persons, keylambda 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这回, 首次进行的计算是 10 加上 1, 此举等同于预先朝着箱子之中放入了一件作为根基铺垫的货物。进行换行操作后, 将加号转变为乘号, 瞬间就成为求乘积的计算把数字替换为字符串, 便形成了拼接。words [ab, cd, ef] print(reduce(lambda a, b: a b, words)) # abcdef记好了, 给你交予的那个合并函数, 始终都仅仅能够收纳两个参数也就是a和b, 倘若多写哪怕一个, 都不会有人传给你, 直接就会报错。千万不要贪心。四件套合体记住这张表回头看它们其实对应了数据处理的四种本能动作• 要统一加工 → map• 要挑三拣四 →• 要排排坐 →• 要合并汇总 →当再次拿到那一堆呈现出紊乱状态的数据时, 不要急急忙忙地去编写for循环。首先, 在内心之中从头到尾梳理一遍, 所面临的需求究竟是对数据进行加工处理、进行筛选操作、进行排序动作、抑或是进行合并工作呢? 然后, 找准对应的车间, 将数据传递进去, 如此一来, 代码量减少了, 思维逻辑也变得清晰明了了。我们来探讨一下, map以及返回的迭代器究竟是什么东西。为何它使用一次就会消失不见了呢? 关于这个在下一篇专题拆解。若感觉内容有用, 无妨先去点个赞收藏起来, 后续运用的时候随手翻找出来便可。