我目前的剧本:
old_ids = []
File.open("missing.txt","w") do |result|
File.open('query_result.csv', "r") do |old_copy|
old_copy.each_line do |line|
old_ids << line.chomp.to_i #add exisiting ids to array
end
end
File.open('item_info', "r") do |new_copy|
new_copy.each_line do |line|
if !old_ids.include? line.split("\t")[0].chomp.to_i #find all ids in new file that do not exist in old file and add them to missing.txt
result.puts line.split("\t")[0].chomp.to_i
puts "Adding #{line.split("\t")[0].chomp.to_i}"
end
end
end
end
如何重构这一点以提高效率。我解析的文件包含大约260万条记录,因此写入时需要很长时间才能执行。
答案 0 :(得分:2)
最低的水果?将Array
和Array#include
替换为Hash
和Hash#key?
:
old_ids = {}
File.open("missing.txt","w") do |result|
File.foreach('query_result.csv') do |line|
id = line.chomp.to_i
old_ids[id] = id
end
File.foreach('item_info') do |line|
id = line.split("\t")[0].chomp.to_i
unless old_ids.key?(id)
result.puts id
puts "Adding #{id}"
end
end
end
原因很简单:Array#include?
每次查找给定值时扫描整个数组,总体上给出O(n 2 )复杂度。另一方面,Hash#key?
计算给定值的哈希值,然后执行查找以查看哈希表中是否存在给定键。摊销时间复杂度接近O(n)。
两者之间的简单测试用例(找到两个文件之间的公共行)产生:
$ time ruby include.rb
real 2m51.409s
user 2m51.246s
sys 0m0.138s
与
$ time ruby key.rb
real 0m0.092s
user 0m0.082s
sys 0m0.009s
这是两个文件,每个文件包含2个 16 行。在10,000行时,include
仍然需要5秒,而key?
需要29毫秒。
有200万行,key?
不到4秒。我认为我不能等待Array#include?
实施完成。
答案 1 :(得分:1)
当您想要检测其他ID时,您距离最佳解决方案还不远。您可以通过构建Set来加速查找,而不是将旧的ID放在数组中。它更快。
old_ids = Set.new
File.open("missing.txt","w") do |result|
File.open('query_result.csv', "r") do |old_copy|
old_copy.each_line do |line|
old_ids.add(line.chomp.to_i) #add exisiting ids to Set
end
end
File.open('item_info', "r") do |new_copy|
new_copy.each_line do |line|
if !old_ids.include? line.split("\t")[0].chomp.to_i #test if the id exists in the Set old_ids
result.puts line.split("\t")[0].chomp.to_i
puts "Adding #{line.split("\t")[0].chomp.to_i}"
end
end
end
end
end
如果没有文件示例,我无法测试。您的代码中存在一个错误(old_wmt_ids)。
答案 2 :(得分:0)
看看Diffy,这是一个很酷的宝石,用于计算文件之间的差异。