我正在尝试对两个文件进行比较,这些文件大约有70k行,而根据我目前的算法,我大约需要5分钟才能完全比较所有文件。
本质上,我正在做的是将两个文件的所有行都放入列表中,这样看起来就这样。
compare_list_new=[['Albert','V4','25.000','45.000','1.3500'],
['James','V4','22.000','43.000','1.4000'], ['James','V5','23.000','41.000','1.3000']]
compare_list_old=[['Albert','V4','25.000','45.000','1.3900'],
['James','V4','22.000','43.000','1.2000'], ['James','V5','23.000','41.000','1.2000']]
这个想法是,两个文件都具有相似的名称,因此要在旧条目中查找新条目,我们必须基于坐标进行搜索,因此,如果我想从新到旧查找特定的James,则必须使用“ 22.000”,“ 43.000”。
找到条目后,我从新文件中取出1.4000,从旧文件中取出1.2000,然后减去它们以从旧文件中找到新文件的增量。
这是当前使用的算法Im:
# This is not important
import time
import timeit
import bisect
from operator import itemgetter
import time
compare=open("factor.output.new.txt","w")
compare_list_new=[]
compare_list_old=[]
newlist=[]
#File Count algorithm
start = time.time() # Tracks execution time
def list_create(fname): #Makes the list in the appropriate format
newlist=[]
with open(fname) as file:
for i, line in enumerate(file):
if i>6:
for line in file:
lines_list=line.split(" ")
del lines_list[0]
del lines_list[2:29]
del lines_list[5:12]
newlist.append(lines_list)
return newlist
#Creates lists and sorts them
compare_list_new=list_create("par_iop.pwr.sfactor.output_new.ipf")
compare_list_new=sorted(compare_list_new, key=itemgetter(2))
compare_list_old=list_create("par_iop.pwr.sfactor.output_old.ipf")
compare_list_old=sorted(compare_list_old, key=itemgetter(2))
compare.write("Name Version Coordinate_x Coordinate_y Sfactordelta FLAG\n")
compare_list_copy=compare_list_old #Makes a copy of the list
for item in compare_list_new: # compares both lists
end = time.time()
print(end - start)
for line in compare_list_old:
if item[0:4] == line[0:4]:
s1=float(item[4])
s2 = float(line[4])
delta=s1-s2
delta=format(delta,'.4f')
item[4]=str(delta)
text = " ".join(item)
compare.write(text +" " +"\n")
compare_list_copy.remove(line)
match=1
break
if(match==1):
compare_list_old=compare_list_copy
match=0
else:
text=" ".join(item)
compare.write(text + " " + "ITEM NOT FOUND IN OLD FILE BUT IS IN NEW FILE""\n")
try:
compare_list_copy.remove(line)
except ValueError:
pass
compare_list_old = compare_list_copy
compare.close()
本质上,将两者进行比较的部分列出了它们是否匹配后对其进行排序的操作,然后它将执行操作以获取增量并将其从副本中删除,然后使旧副本等于副本,从而使其不等于副本遍历列表时删除项目。如果该项目不匹配,则表示该项目不在旧文件中,而是在新文件中。
我想要一些可能使此过程更快的东西。
答案 0 :(得分:3)
这里有很多代码,而且缩进显然是不正确的,所以我什至不知道逻辑到底应该是什么,也没有迹象表明您认为哪一部分很慢(或者您怎么知道),但是一件事立即跳了出来:
compare_list_copy.remove(line)
…和另一个remove
。
首先,每当您调用lst.remove(val)
时,列表都必须进行线性搜索,将每个元素与val
进行比较。但是您已经知道想要的元素的索引(或者,仅使用enumerate
,您就可以知道它们的索引),因此浪费了整个搜索时间;只是del lst[idx]
。
第二,无论您是remove
还是del
,您仍在从数组中间删除。这意味着将所有后续元素上移一个插槽。它有一个快得多的常量(这只是一个很大的记忆,而不是一堆对比较函数的调用),但是它仍然是线性的。
您正在内部循环中执行此操作。因此,您正在将N
的额外因数乘以已经是二次的时间。如果您只是在对数搜索中对相同数据进行线性搜索,那么您浪费大量精力进行对数搜索而不是通过bisect
进行线性时间搜索就会浪费掉。
如果您需要某些内容,可以在对数时间进行搜索,也可以在对数时间进行修改,则需要的是某种树(或树列表结构,例如跳过列表)。有很好的库在PyPI上包装了各种二叉树和b树变体,或者您可以在Wikipedia上查找算法。
或者,您也可以像Sorted Containers库之类的东西来抓取更高级别的内容。例如,sorteddict
的行为与dict
很相似,但是您可以搜索最接近的键而不是完全匹配的键,也可以搜索给定范围内的所有键,等等。带有某种混合式的斜拉绳之类的东西,但您无需关心这些细节;重要的是它可以保证您在对数时间内所需的所有操作。
完成此操作后,两个外循环中的至少一个也可以从对数搜索中获利(使用树几乎可以免费获得对数搜索)。
此时您的总时间为O(log**2 N * N)
,而不是O(N**3)
,这是一个巨大的差异。
如果您不习惯用算法复杂度来处理性能,请考虑以下问题:只有1000个元素,立方时间需要1000*1000*1000
= 10亿步;对数平方线性时间为10*10*1000
= 10万步。那是几天和几秒钟之间的区别。
答案 1 :(得分:1)
您的当前比较至少是二次的(由于嵌套循环)。从第一个列表(线性时间)生成字典的速度更快,在第一个列表中,键是名称的元组和前两个坐标(对于新文件和旧文件,它们似乎相同),然后对于在第二个列表中,检查该键是否在字典中(再次是线性时间)。
答案 2 :(得分:0)
compare_list_new = [['Albert', 'V4', '25.000', '45.000', '1.3500'],
['James', 'V4', '22.000', '43.000', '1.4000'],
['James', 'V5', '23.000', '41.000', '1.3000']]
compare_list_old = [['Albert', 'V4', '25.000', '45.000', '1.3900'],
['James', 'V4', '22.000', '43.000', '1.2000'],
['James', 'V5', '23.000', '41.000', '1.2000']]
d = {}
for l in compare_list_old:
# construct tuple as key and value as 'float' value
d[tuple(l[0:3])] = l[4]
print(d)
# {('Albert', 'V4', '25.000'): '1.3900', ('James', 'V4', '22.000'): '1.2000', ('James', 'V5', '23.000'): '1.2000'}
print(d[('Albert', 'V4', '25.000')])
# 1.3900
for item in compare_list_new:
old_float_val = d[tuple(item[0:3])]
new_float_val = item[4]
# continue whatever calculation here
想法是用键和值将旧列表构造为字典。 这样,我们就不会相对于第一个列表重复第二个列表。
答案 3 :(得分:-1)
您是否考虑过使用difflib库来解决您的问题?
如果您能尝试一下,我期待听到表演。