我正在将2个文件与初始标识符列,起始值和结束值进行比较。第二个文件包含相应的标识符和另一个值列。
实施例。
文件1:
A 200 900
A 1000 1200
B 100 700
B 900 1000
文件2:
A 103
A 200
A 250
B 50
B 100
B 150
我想找到第二个文件中包含在第一个文件中找到的范围内的所有值,以便我的输出看起来像:
A 200
A 250
B 100
B 150
现在我已经从第一个文件创建了一个包含范围列表的字典: 实施例
if Identifier in Dictionary:
Dictionary[Identifier].extend(range(Start, (End+1)))
else:
Dictionary[Identifier] = range(Start, (End+1))
然后我浏览第二个文件并搜索范围字典中的值: 实施例
if Identifier in Dictionary:
if Value in Dictionary[Identifier]:
OutFile.write(Line + "\n")
虽然不是最优的,但这适用于相对较小的文件,但是我有几个大文件,这个程序证明非常低效。我需要优化我的程序,以便它运行得更快。
答案 0 :(得分:2)
from collections import defaultdict
ident_ranges = defaultdict(list)
with open('file1.txt', 'r') as f1
for row in f1:
ident, start, end = row.split()
start, end = int(start), int(end)
ident_ranges[ident].append((start, end))
with open('file2.txt', 'r') as f2, open('out.txt', 'w') as output:
for line in f2:
ident, value = line.split()
value = int(value)
if any(start <= value <= end for start, end in ident_ranges[ident]):
output.write(line)
备注:使用defaultdict
可以在不首先检查密钥是否存在的情况下为字典添加范围。使用any
可以缩短范围检查。使用链式比较是一个很好的Python语法快捷方式(start <= value <= end
)。
答案 1 :(得分:0)
由于你有很大的范围而你的问题基本上只是一堆比较,所以存储开始/结束元组几乎肯定比整个范围更快(特别是因为你现在拥有的将会复制大部分的如果两个碰巧重叠,则范围内的数字。)
# Building the dict
if not ident in d:
d[ident] = (lo, hi)
else:
old_lo, old_hi = d[ident]
d[ident] = (min(lo, old_lo), max(hi, old_hi))
然后你的比较看起来像:
# comparing...
if ident in d:
if d[ident][0] <= val <= d[ident][1]:
outfile.write(line+'\n')
如果您不对if ident in d
进行单独检查,则此部分的两个部分都会更快。 Python字典很好而且速度很快,所以只需要调用它就可以了。您可以为字典提供默认值,因此请使用它。我没有对这个或任何事情进行基准测试,看看加速是什么,但你肯定会得到一些,它肯定有效:
# These both make use of the following somewhat silly hack:
# In Python, None is treated as less than everything (even -float('inf))
# and empty containers (e.g. (), [], {}) are treated as greater than everything.
# So we use the tuple ((), None) as if it was (float('inf'), float('-inf))
for line in file1:
ident, lo, hi = line.split()
lo = int(lo)
hi = int(hi)
old_lo, old_hi = d.get(ident, ((), None))
d[ident] = (min(lo, old_lo), max(hi, old_hi))
# comparing:
for line in file2:
ident, val = line.split()
val = int(val)
lo, hi = d.get(ident, ((), None))
if lo <= val <= hi:
outfile.write(line) # unless you stripped it off, this still has a \n
以上代码是我用来测试的;它会在几秒钟内在file2
百万行上运行。
答案 2 :(得分:0)
你需要构建range(START, END)
吗?当你可以这样做时,这似乎很浪费:
if START <= x <= END:
# process
检查值是否在范围内是因为a)您必须构建列表并且b)对列表执行线性搜索以找到它。
答案 3 :(得分:0)
您可以尝试这样的事情:
In [27]: ranges=defaultdict(list)
In [28]: with open("file1") as f:
for line in f:
name,st,end=line.split()
st,end=int(st),int(end)
ranges[name].append([st,end])
....:
In [30]: ranges
Out[30]: defaultdict(<type 'list'>, {'A': [[200, 900], [1000, 1200]], 'B': [[100, 700], [900, 1000]]})
In [29]: with open("file2") as f:
for line in f:
name,val=line.split()
val=int(val)
if any(y[0]<=val<=y[1] for y in ranges[name]):
print name,val
....:
A 200
A 250
B 100
B 150
答案 4 :(得分:0)
巧妙的技巧:Python允许您与in
个对象进行xrange
比较,这比使用in
进行range
快得多,并且内存效率更高。< / p>
所以,你可以做到
from collections import defaultdict
rangedict = defaultdict(list)
...
rangedict[ident].append(xrange(start, end+1))
...
for i in rangedict:
for r in rangedict[i]:
if v in r:
print >>outfile, line