如何对迭代器去重?含glob文件匹配迭代器去重实现问询
对迭代器去重的实现方案
当然可以对迭代器进行去重,但要结合迭代器单向、懒加载的特性来设计方案。针对你用iglob处理大量文件的场景,我提供两种实用方案,兼顾去重需求和内存效率:
方案一:懒加载式去重(推荐)
这种方案会在遍历迭代器的过程中实时记录已出现的文件名,既保留iglob的懒加载优势,又实现去重——内存只需要存储已经见过的文件名,对于几千个文件来说,内存开销可以忽略。
我们可以写一个通用的去重生成器,然后包装你的glob_everything返回的迭代器:
import itertools as it from glob import iglob def unique_iterator(iterator): seen = set() for item in iterator: # 检查当前文件名是否已出现过 if item not in seen: seen.add(item) yield item def glob_everything(filelist): # 用unique_iterator包装链式迭代器,实现去重 return unique_iterator(it.chain.from_iterable(iglob(f) for f in filelist)) # 测试代码 parmfiles = "somefile.txt *.txt" files = parmfiles.split() for file in glob_everything(files): print('3', file)
这个方案的核心是:迭代器依然是懒加载的,只有当你遍历到某个文件时,才会检查它是否重复,不重复就返回。完全不会一次性加载所有文件到内存,完美契合你用iglob的初衷。
方案二:提前全量去重(适合文件数量较少的场景)
如果你确实需要在开始处理前就完成所有去重,那只能先把所有匹配的文件加载到集合中(集合天然去重),再转成迭代器。但这样会失去iglob的懒加载优势,所有文件会一次性进入内存,适合文件数量不多的情况:
import itertools as it from glob import iglob def glob_everything(filelist): # 一次性拉取所有文件到集合去重,再转成迭代器 all_unique_files = set(it.chain.from_iterable(iglob(f) for f in filelist)) return iter(all_unique_files) # 测试代码 parmfiles = "somefile.txt *.txt" files = parmfiles.split() for file in glob_everything(files): print('3', file)
两种方案的对比
| 方案 | 内存效率 | 去重时机 | 适用场景 |
|---|---|---|---|
| 懒加载去重 | 高(仅存已遍历文件名) | 遍历过程中实时去重 | 大量文件,需要保持内存友好 |
| 提前全量去重 | 低(加载所有文件) | 遍历前完成全部去重 | 文件数量少,需要提前确认所有唯一文件 |
关键说明
为什么不能在不遍历迭代器的情况下提前完成去重?因为迭代器的元素是按需生成的,在遍历之前,元素并没有实际存在,所以无法提前检查重复。这是迭代器的核心特性决定的,所以懒加载式去重是更贴合迭代器设计的方案。
内容的提问来源于stack exchange,提问作者vr8ce
相关产品推荐
相关产品推荐

