Python移除列表重复元素且保留首尾实例的更Pythonic实现方式
移除列表重复元素(仅保留目标元素首尾实例)的Pythonic实现
原有实现的潜在问题
你提供的两种写法都存在索引偏移的隐患:
- 第一种实现正向遍历删除索引时,删除靠前的元素后,后续元素的索引会整体前移,当目标重复次数≥3时会出现删错甚至
IndexError的问题 - 第二种实现遍历切片
lst[1:-1]时,切片是原列表的浅拷贝快照,删除原列表元素后遍历逻辑会漏判后续元素,相邻重复场景下会失效
更Pythonic的实现方案
推荐直接构建新列表的方式,时间复杂度O(n),没有索引偏移问题,可读性也更高:
场景1:仅针对单个指定目标元素过滤
lst = ["foo", "bar", "foobar", "foo", "barfoo", "foo"] target = "foo" # 取目标元素第一次和最后一次出现的索引 first_idx = lst.index(target) last_idx = len(lst) - 1 - lst[::-1].index(target) # 生成过滤后的新列表 res = [ val for idx, val in enumerate(lst) if idx in (first_idx, last_idx) or val != target ] print(res) # 输出:['foo', 'bar', 'foobar', 'barfoo', 'foo']
场景2:对列表中所有元素都执行「保留首尾、删除中间重复」
如果需要处理所有元素的重复,而非单个目标,可以用collections.defaultdict记录每个元素的出现位置再过滤:
from collections import defaultdict lst = ["foo", "bar", "foo", "bar", "foobar", "bar"] pos_map = defaultdict(list) # 记录每个元素所有出现的索引 for idx, val in enumerate(lst): pos_map[val].append(idx) # 生成白名单索引:所有元素的首尾出现位置 keep_idx = set() for positions in pos_map.values(): keep_idx.add(positions[0]) keep_idx.add(positions[-1]) res = [val for idx, val in enumerate(lst) if idx in keep_idx] print(res) # 输出:['foo', 'bar', 'foobar', 'bar']
原实现修复方案
如果你一定要在原列表上执行删除操作,需要倒序遍历要删除的索引,避免索引偏移:
lst = ["foo", "bar", "foobar", "foo", "barfoo", "foo"] occurence = [i for i, e in enumerate(lst) if e == "foo"] to_remove = occurence[1:-1] # 倒序删除就不会出现索引错位问题 for i in reversed(to_remove): del lst[i] print(lst) # 输出:['foo', 'bar', 'foobar', 'barfoo', 'foo']
内容的提问来源于stack exchange,提问作者o.sk
相关产品推荐
相关产品推荐

