我有一个很大的文本文件(coverage.txt)> 2G,看起来像这样:
#RefName Pos Coverage
BGC0000001_59320bp 0 0
BGC0000001_59320bp 1 0
BGC0000002_59320bp 2 0
BGC0000002_59320bp 3 0
BGC0000002_59320bp 4 0
BGC0000003_59320bp 5 0
BGC0000003_59320bp 6 0
BGC0000003_59320bp 7 0
BGC0000004_59320bp 8 0
BGC0000004_59320bp 7 0
BGC0000004_59320bp 8 0
BGC0000005_59320bp 7 0
BGC0000005_59320bp 8 0
BGC0000005_59320bp 7 0
BGC0000006_59320bp 8 0
BGC0000006_59320bp 7 0
BGC0000006_59320bp 8 0
BGC0000007_59320bp 7 0
BGC0000007_59320bp 8 0
BGC0000007_59320bp 7 0
BGC0000008_59320bp 8 0
BGC0000008_59320bp 7 0
BGC0000008_59320bp 8 0
BGC0000009_59320bp 7 0
BGC0000009_59320bp 8 0
我还有另一个文本文件(rmList.txt),如下所示:
BGC0000002
BGC0000004
BGC0000006
BGC0000008
如果这些行包含rmList.txt中的ID,我想从我的coverage.txt文件中删除这些行。
这是我尝试过的:
wanted = [line.strip() for line in open('rmList.txt')]
files = 'coverage.txt'
def rmUnwanted(file):
with open(file) as f, open('out.txt', 'w') as s:
for line in f:
pos = line.split()[0].split('_')[0]
if pos not in wanted:
s.write(line)
rmUnwanted(files)
但这对于我的大文件来说是永远的。有一个更好的方法吗?我的代码有什么问题吗?
非常感谢您!
答案 0 :(得分:0)
使用set而不是list来检查重复的元素。
wanted = { line.strip() for line in open('rmList.txt') }
....
答案 1 :(得分:0)
在我看来,代码没有错,它可以满足您的要求。但是,大文件将需要时间。 您仍然可以提高效率。
如果您确定两个文件都已排序(如您的示例所示),则此代码应更快:
def rmUnwanted(file):
with open(file) as f, open('out.txt', 'w') as s:
i = 0
lastwanted = ""
for line in f:
pos = line.split()[0].split('_')[0]
try:
if pos not in [wanted[i], lastwanted]:
s.write(line)
else:
if pos == wanted[i]:
lastwanted = wanted[i]
i = i+1
except IndexError:
s.write(line)
使用您提供的示例文件可以得到相同的结果,但是速度更快(我没有测量,但是应该)。
我在这里要做的是避免在每次迭代时都在整个pos
列表中寻找wanted
,如果您的实际rmList.txt也很大,那会很费时间。
答案 2 :(得分:0)
您可以执行以下操作:
with open("rmLst.txt") as f:
rmLst = set(f.readlines())
with open("out.txt", "w") as outf, open("coverage.txt") as inf:
# write header
outf.write(next(inf))
# write lines that do not start with a banned ID
outf.writelines(line for line in inf if line[:line.index("_")] not in rmList)
首先,将要删除的所有ID存储在一组中以进行快速查找。然后,遍历行并检查每行是否以错误的ID开头。请注意,我们可以运行line.split()
来检查访问每一行的ID部分,而不是运行line[:line.index['_']]
。这样可以避免创建每行的副本,并且应比split
更快。如果所有ID的长度都是固定的,则可以用数字替换line.index['_']
。