听着像是很简单的需求:“给list_1里的元素把不在list_2里的都删掉”,可实际操作里却总是掉坑里。举个例子,给出两个这样的列表:list_1里头装着魁哥、夭夭、阿离、渣姐、秃头企鹅、王哥、小白、卷魔,而list_2里只有旺仔、秃头企鹅、王哥。按说理想的结果应该是只剩秃头企鹅和王哥,但是直接写个for循环去删除,往往会漏删,甚至还会出现IndexError这种越界的情况。 为啥会这样呢?比如你按照常规思路写个循环:for i in list_1: if i not in list_2: list_1.remove(i),结果运行出来一看,'夭夭'、'渣姐'、'卷魔'这几个还在列表里,原因就在于删除元素后列表的长度变短了,后面的元素往前挤,可for循环的指针还在按原来的顺序往下走,结果自然就会漏掉本来应该被删掉的元素。 换成下标循环也不灵光,range(len(list_1))生成的索引数本来是对的,但每删除一次元素后长度减一,到最后一个索引时肯定会报错,提示IndexError: list index out of range。 别急,下面给你支四招: 第一招叫下标加继续迭代。你可以定义一个变量j从0开始,用while循环判断j是否小于列表长度。如果发现当前元素不在list_2里,就直接用remove删掉它;如果在,就让j加1接着往后走。这么做的好处是逻辑很直观,把每次的删除过程打印出来看一眼就能清楚明白。最后剩下的就只有['秃头企鹅', '王哥']。 第二招是倒序遍历,这个方法最省心。你可以用range(len(list_1)-1, -1, -1)倒着数数,从最后一个元素开始往前检查。不管删多少个元素,下标只会越来越小,永远都不会超出范围导致越界错误。运行完同样能得到正确的结果。 第三招有点粗暴,叫作无限循环加break。你可以设置一个无限while True循环,在里面再套一个for循环遍历list_1。只要发现元素不在list_2里,就立即把它删掉然后break跳出内层循环;如果内层循环都跑完了没有break(也就是整个列表都检查过了),就再break跳出外层的无限循环。虽然看着有点笨,但保证了一次性把不符合条件的元素全部清空。 最后一招是字典加推导式,这个办法最灵活。先把list_1用字典存起来,用下标做键值对里的键,元素做值。然后遍历字典里的每一项,把不在list_2里的元素对应的键值对都置为空列表。最后用推导式把字典里剩下的非空值收集起来就行了。这一过程顺带复习了字典、推导式还有enumerate这些高频考点。 方案一适合处理小范围的数据量,逻辑特别清晰;方案二只需要一行代码就能搞定越界问题,面试的时候拿来写手撕代码很加分;方案三直接用一行代码清空列表,在内存比较紧张的场景下跑得更快;方案四则是字典和推导式的结合体,拿来复习知识点再合适不过了。 建议大家把这四种方案都亲自抄进编辑器跑一遍代码,再自己加几组边界数据去测试一下。只要把“遍历加删除”这块的坑都填平了,以后代码就不太容易翻车啦!祝你周末愉快!