Python列表边遍历边修改问题解决方案:alist[:]

最近在看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[:]的地址,果然不同。
1115880-20180420234412505-1282836694.jpg

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函数进行过滤处理,实现对列表的过滤功能。

转载于:https://www.cnblogs.com/HZL2017/p/8894215.html

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
保持升序排列。 解决方案: 链表的排序可以使用冒泡排序、插入排序、选择排序等算法,这里我们采用插入排序的方法实现。 插入排序的基本思路是:将未排序的元素一个一个插入到已排序的序列中,直到所有元素都被排序为止。 具体实现过程如下: 1. 定义一个新的链表,作为排序后的结果链表。 2. 遍历原链表,依次取出每个结点,将其插入到新链表中的合适位置。 3. 插入结点时,从新链表的头结点开始遍历,找到第一个比待插入结点大的结点,将待插入结点插入到该结点的前面。 4. 将所有结点都插入到新链表中后,返回新链表的头结点即为排序后的链表。 两个有序链表的合并可以使用归并排序的思想,将两个有序链表分别按照升序排列,然后再将它们合并成一个有序链表。 具体实现过程如下: 1. 定义一个新的链表,作为合并后的结果链表。 2. 分别遍历两个有序链表,比较它们的结点大小,将小的结点插入到新链表中。 3. 如果其中一个链表已经遍历完了,将另一个链表剩余的结点直接插入到新链表中。 4. 返回新链表的头结点即为合并后的有序链表。 示例代码如下(以排序为例): ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def sortList(head: ListNode) -> ListNode: if not head or not head.next: return head # 定义一个新链表作为结果链表 dummy = ListNode(0) dummy.next = head cur = head.next head.next = None # 遍历原链表 while cur: next = cur.next pre = dummy while pre.next and pre.next.val < cur.val: pre = pre.next cur.next = pre.next pre.next = cur cur = next return dummy.next def mergeTwoLists(l1: ListNode, l2: ListNode) -> ListNode: dummy = ListNode(0) cur = dummy while l1 and l2: if l1.val <= l2.val: cur.next = l1 l1 = l1.next else: cur.next = l2 l2 = l2.next cur = cur.next if l1: cur.next = l1 else: cur.next = l2 return dummy.next ``` 以上代码实现了链表的排序和两个有序链表的合并,时间复杂度都是 O(nlogn),其中 n 是链表的长度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值