当前位置: 首页 > 后端技术 > Python

一题让你真正理解Python编程

时间:2023-03-26 18:31:38 Python

那首远方耳熟能详的歌,为什么那些声音那么微弱。好久不见。你现在怎么样?有没有这样一首歌,能让你轻轻跟随,唱出主题曲,伴随着我们人生的酸甜苦辣;有没有这样一首歌,会让你突然想起我,让你开心,让你担心,所以Oneme……音乐结束,回到正题。最近浏览了LeetCode,发现一个很有意思的小题目。当我试图用Python回答时,我实际上使用了集合、映射函数、zip函数、lambda函数和排序函数。调试过程中还涉及到迭代器、生成器和列表推导的概念。一个看似极其简单的题目,虽然最终代码可以组合成一行,但几乎用了一次Python编程技巧。可谓是“细微处见精神”!通过这个话题,也许你会从此真正了解Python编程。这个问题叫做《列表中的幸运数》。什么是幸运数字?在整数列表中,如果一个数字与其值出现的频率相同,我们称该数字为“幸运数字”。比如在列表[1,2,2,3]中,数字1和2分别出现了1和2,所以是幸运数字,但是3只出现了一次,3不是幸运数字。现在我们了解了幸运数字的概念,让我们尝试在列表[3,5,2,7,3,1,2,4,8,9,3]中找到幸运数字。这个过程可以分为以下几个步骤:找到列表中的唯一数字统计每个数字在列表中出现的次数找出那些出现次数等于数字本身的数字Step1找到列表中的唯一数字list找出列表中不重复的数字,即去掉列表中重复的元素,简称“去重”。最干净的去重方法是使用集合。>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>unique=set(arr)>>>unique{1,2,3,4,5,7,8,9}第二步,统计每个数字在列表中出现的次数我们知道列表对象有一个count()方法可以返回一个元素在列表中出现的次数,具体用法如下:>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>arr.count(8)#元素8出现在数组arr2次2之后,我们只需要遍历去重后的每个元素,一个一个统计每个元素出现的次数,存成合适的数据结构,这一步就万事大吉了.>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>unique=set(arr)#删除重复元素>>>pairs=list()#空列表,用于保存数组元素和出现次数组成的元组>>>foriinunique:pairs.append((i,arr.count(i)))>>>pairs[(1,1),(2,2),(3,3),(4,1),(5,1),(7,1),(8,2),(9,1)]作为新手,代码是写成这样,已经很不错了。然而,一个有抱负的程序员永远不会自满和停滞不前。他们最喜欢做的就是千方百计消除for循环,比如用映射函数和过滤函数来代替for循环;即使无法拒绝for循环,他们也会尽可能地隐藏循环,例如隐藏在列表推导中。由于这里要为每个元素调用列表的count()方法,所以用map函数代替for循环是最合适的。>>>m=map(arr.count,unique)>>>m>>>list(m)#生成器可以转换成列表[1,2,3,1,1,1,2,1]>>>list(m)#生成器只能使用一次,使用后自动清理[]map函数返回一个生成器(generator),可以像列表一样遍历,但不能像列表一样直观的看到每一个元素,除非我们用list()把这个生成器转成列表(实际上没必要把生成器转成列表)。请注意,生成器不同于迭代器,或者说生成器是一种特殊的迭代器,只能遍历一次,遍历结束后自动消失。迭代器可以迭代。例如,range()函数返回一个迭代器:>>>a=range(5)>>>list(a)[0,1,2,3,4]>>>list(a)[0,1,2,3,4]说完了生成器和迭代器,我们又要回到原来的话题了。使用map映射函数,我们得到每个元素出现的次数,我们需要和对应的元素组成一个元组。这时候就用到了zip()函数。zip()函数创建一个生成器,它聚合每个可迭代对象(迭代器、生成器、列表、元组、集合、字符串等)的元素。具有最短可迭代对象长度的元素。>>>m=map(arr.count,unique)>>>z=zip(unique,m)>>>z>>list(z)[(1,1),(2,2),(3,3),(4,1),(5,1),(7,1),(8,2),(9,1)]>>>list(z)[]是很明显,zip()函数返回的也是一个生成器,只能使用一次,然后就消失了。第三步,找出那些出现次数等于这个数本身的数有了每个元素和它的出现次数,我们只需要循环遍历……不对,等一下,为什么要循环呢?我们只需要过滤每个元素并找到那些出现次数等于元素本身的元组。为什么不试试过滤函数filter()呢?>>>deffunc(x):#参数x是元组类型ifx[0]==x[1]:returnx>>>m=map(arr.count,unique)>>>z=zip(unique,m)>>>f=filter(func,z)>>>f>>>list(f)[(1,1),(2,2),(3,3)]>>>list(f)[]过滤函数filter()接受两个参数。第一个参数是一个函数,用来判断一个元素是否满足过滤条件。第二个参数是要过滤的可迭代对象。filter()函数也返回一个生成器,只能使用一次,然后就消失了。写到这里,我们差不多完成了。然而,作为一个有抱负的程序员,你能容忍func()这样一个看起来怪怪的函数吗?答案是不!您肯定会用lambda函数替换它。另外,也许我们还需要根据元素的大小对结果进行排序。加上排序,完整代码如下:>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>unique=set(arr)>>>m=map(arr.count,unique)>>>z=zip(unique,m)>>>f=filter(lambdax:x[0]==x[1],z)>>>s=sorted(f,key=lambdax:x[0])>>>print('幸运数字是:',[item[0]foritemins])幸运数字是:[1,2,3】终极代码,一行搞定如果你曾经有过被那些一行写出的可以实现复杂功能,看起来像圣经的代码蹂躏的惨痛经历,那么现在你也可以把上面的代码写成一根线去蹂躏别人。>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>print('幸运数字是:',[item[0]foritem在sorted(filter(lambdax:x[0]==x[1],zip(set(arr),map(arr.count,set(arr)))),key=lambdax:x[0])])幸运数字是:[1,2,3]戏剧性的逆转,这次我真的懂Python了!有人说,何苦呢?这样写不是更简单,更易读吗?果然是我真的想多了!>>>arr=[3,5,2,7,3,8,1,2,4,8,9,3]>>>[xforxinset(arr)ifx==arr.count(X)]