最近在看python,遇到个简单的问题:删除列表中指定的重复元素,发现一些实用并且有趣的东西。

1.错误示范

alist = [1,1,2,2,3,3,2,2,1,1]
for i in alist:
if i ==1:
alist.remove(1)
print(alist)

运行结果:[2, 2, 3, 3, 2, 2, 1, 1]

错误原因:删除列表元素,导致列表内容改变,部分元素位置前移;当继续进行for循环时,索引继续加一,导致跳过一个元素。

本例中,第二个“1”和第四个“1”被跳过,但是remove()是删除从列表第一个出现的元素,所以当第三个“1”出现进入if语句时,第二个“1”被删除。

2.解决方法一:alist[1]

alist = [1,1,2,2,3,3,2,2,1,1]
for i in alist[:]: ###
if i ==1:
alist.remove(1)
print(alist)

运行结果:[2, 2, 3, 3, 2, 2]

简析:将for循环中的控制语句改成" for i in alist[:]"后,程序正确实现功能。对于这个很神奇的alist[:],查了好久,都没有找到相关资料。后来,在和朋友的讨论中,我突然想到“地址”的抽象概念。错误实现的语句" for i in alist"中的"alist",是列表的名称,类似于C中的数组名,其实可以看做一个指向该列表的指针,执行for循环时不断地通过这个地址找到对应元素,导致出现错误结果。

然而," for i in alist[:]"中,“alist[:]”是将alist中的所有元素取出,存储在另一块独立与alist的区域中,这样的话,当修改原列表alist时,并不会修改for循环的判断逻辑,其实就是相当于alist复制给一个新的列表,利用新的列表进行for循环的控制。

为验证以上猜想,用id()命令分别查看alist 和 alist[:]的地址,果然不同。

3.解决方案二:定义一个新的列表

alist = [1,1,2,2,3,3,2,2,1,1]
alist_new = []
for i in alist:
if i!=1:
alist_new.append(i)
alist = alist_new
print (alist)

运行结果:[2, 2, 3, 3, 2, 2]

简析:定义一个新的列表,将不满足条件的值添加到新表中,遍历原列表后,将新列表覆盖原列表。

缺点:新列表会占用内存

4.解决方法三:改变循环条件

alist = [1,1,2,2,3,3,2,2,1,1]
i = 0
while i<len(alist):
if alist[i]==1:
alist.pop(i)
i = i-1
i = i+1
print (alist)

运行结果:[2, 2, 3, 3, 2, 2]

简析:改变循环条件,判断是否遍历完成,如果删除一个元素,后面元素前移,此时令循环条件i减1,再次判断当前位置,正好判断的是后移过来的新元素。直到所有元素全部遍历。

缺点:逻辑稍复杂,比较优化

5.解决方法四:利用while循环和in、index()函数

alist = [1,1,2,2,3,3,2,2,1,1]
while 1 in alist :
alist.pop(alist.index(1))
print (alist)

运行结果:[2, 2, 3, 3, 2, 2]

简析:(1)关键字in,判断一个元素是否在一个集合中,返回True/False;同理,not in也是判断一个元素是否不在一个集合中,返回True/False;有一个类似的关键字 is,判断两个变量是否是同一对象,即同一内存空间,或者地址相同,同样有not is。

(2)index()方法,返回元素在序列中第一次出现的索引号,如果元素不存在于序列中,则会报出异常。

(3)pop() 函数用于移除列表中的一个元素(可用需要删除的索引号作为输入参数,默认删除最后一个元素),并且返回该元素的值。

(4)逻辑:在while条件中不断判断列表中是否有目标元素,若有,则用index()找到该元素的索引号,并用pop()删除,直到删除干净。

6.解决方法五:利用filter()和labmbda

alist = [1,1,2,2,3,3,2,2,1,1]
alist = list(filter(lambda x: x!=1, alist))
print (alist)

运行结果:[2, 2, 3, 3, 2, 2]

简析:(1)根据题目要求,就是对列表进行过滤处理,很自然地想到了filter()函数,配合lambda表达式简直完美。

(2)filter()函数:用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

用法:filter(function, iterable)

(3)lambda:匿名定义简单函数,主体是一个表达式,常用于函数式编程。

用法:lambda [arg1 [,arg2,.....argn]]:expression

(4)逻辑:用lambda定义匿名函数,判断元素是否为非“1”,若真则返回True,否则返回False。在用filter函数进行过滤处理,实现对列表的过滤功能。

Python列表边遍历边修改问题解决方案:alist[:]的更多相关文章

  1. Python列表:元素的修改、添加、删除和排序

    本文参考自<Python编程:从入门到实践>,作者:Eric Matthes,译者:袁国忠 操作 语法 举例 结果 修改元素   motocycles = ['honda', 'yamah ...

  2. python列表之添加、修改和删除元素

    修改列表中的元素: subject= ['math', 'Chinese', 'English'] subject[0] = 'history' # 列表名[要修改元素的下标]=修改后的元素 prin ...

  3. 【代码学习】PYTHON 列表循环遍历及列表常见操作

    一.for循环 为了更有效率的输出列表的每个数据,可以使用循环来完成 代码: A = ['xiaoWang','xiaoZhang','xiaoHua'] for tempName in A: pri ...

  4. Python列表简介和遍历

    一.Python3列表简介 1.1.Python列表简介 序列是Python中最基本的数据结构 序列中的每个值都有对应的位置值,称之为索引,第一个索引是0,第二个索引是1,以此类推. Python有6 ...

  5. Python面试题目之(针对dict或者set数据类型)边遍历 边修改 报错dictionary changed size during iteration

    # result 是一个字典, 把里面属性值是None的属性删除 for key in result: if not result[key]: del result[key] continue 但是报 ...

  6. python列表和字符串的三种逆序遍历方式

    python列表和字符串的三种逆序遍历方式 列表的逆序遍历 a = [1,3,6,8,9] print("通过下标逆序遍历1:") for i in a[::-1]: print( ...

  7. python创建与遍历List二维列表

    python创建与遍历List二维列表 觉得有用的话,欢迎一起讨论相互学习~Follow Me python 创建List二维列表 lists = [[] for i in range(3)] # 创 ...

  8. python 三种遍历列表里面序号和值的方法

    list = ['html', 'js', 'css', 'python'] # 方法1 # 遍历列表方法1:' for i in list: print("序号:%s 值:%s" ...

  9. python中for循环里去修改列表注意的事项

    你的微信好友当中有 5 个推销的,他们存在一个列表 # black_list=['卖茶叶', '卖面膜', '卖保险', '卖花生', '卖手机'] # 当中, 请把这 5 个人分别从 black_l ...

随机推荐

  1. java枚举enum equal与==

    原文链接:https://www.cnblogs.com/xiohao/p/7405423.html 问题 我知道Java枚举会被编译成一个包含私有构造参数和一堆静态方法的类,当去比较两个枚举的时候, ...

  2. SP705 SUBST1 - New Distinct Substrings

    \(\color{#0066ff}{ 题目描述 }\) 给定一个字符串,求该字符串含有的本质不同的子串数量. \(\color{#0066ff}{输入格式}\) T- number of test c ...

  3. 编译 OpenWrt/LEDE 基本过程

    说明 前段时间花 110 从闲鱼淘了个 Newifi D1,这个路由的 Soc 是 MT7621AT,性能强劲,于是又开始折腾编译固件了,重新记录一下编译基本过程. 步骤 安装必要的软件包 sudo ...

  4. C语言中的头文件

    1.头文件#include <> :表示引用标准库头文件,编译器会从系统配置的库环境中去寻找 2.头文件#include "":一般表示用户自己定义使用的头文件,编译器 ...

  5. Python十大应用领域与就业方向

    参考链接:https://baijiahao.baidu.com/s?id=1604847283884842928&wfr=spider&for=pc 正文: 近些年,编程语言Pyth ...

  6. 基于Visual Studio .NET2015的单元测试 OpenCover

    https://www.cnblogs.com/XiaoRuLiang/p/10095723.html 基于Visual Studio .NET2015的单元测试 1.    在Visual Stud ...

  7. n阶乘,位数,log函数,斯特林公式

    一.log函数 头文件: #include <math.h> 使用: 引入#include<cmath> 以e为底:log(exp(n)) 以10为底:log10(n) 以m为 ...

  8. Linux UDEV提权过程

    1.下载攻击脚本 [test@H0f ~]$ wget http://www.extmail .org/source/exploit-udev-8478 --2018-04-02 01:21:00-- ...

  9. Sean McGinnis

    * Loaded log from Wed Nov 25 22:19:43 2015 * Now talking on #openstack-smaug* [smcginnis] (~smcginni ...

  10. (转)AIX修改系统时区的3种方法和AIX 时间问题(夏令时)

    原文:http://blog.csdn.net/fuwencaho/article/details/28267283 http://www.wo81.com/tec/os/aix/2014-04-30 ...