这是 Ruby 中的一种方法。这个想法是创建一个散列,其键是文件#2 行的散列码,其值是文件中的偏移量数组,该文件开始具有由键给出的散列码的行。这些数组中的大多数当然会包含一个偏移量,但我们必须考虑这样一个事实,即不同的字符串可能具有相同的哈希码,这种可能性从唯一哈希码的数量是有限的这一事实中可以明显看出,而唯一字符串的数量是无限的。
可以想象,文件 #2 太大以至于无法将这个哈希值保存在内存中。如果是这种情况,则必须修改下面描述的方法以将哈希的内容保存在数据库中,并由键索引。
首先让我们创建一个文件 #2 的示例。
str =<<~_
Now is the time
for all good coders
to come to the aid
of their fellow coders
_
F2_NAME = 'test'
File.write(FNAME, str)
#=> 78
假设我们要计算以下内容。
require 'set'
hash_codes_in_F2 = File.foreach(F2_NAME)
.with_object(Set.new) { |line, s| s << line.chomp.hash }
#=> #<Set: {2098464159550983171, -1174471330590153942,
# -2185914657312873106, 4309024537421084150}>
我们计算过,例如:
"Now is the time".hash
#=> 2098464159550983171
请参阅 Set::new 和 String#hash。
暂时假设每个字符串都有一个唯一的哈希码,我们知道这通常可能不是真的。我们可以简单地计算文件 1 中每一行的哈希码,看看它是否是集合 hash_codes_in_F2 的成员,每次查找都非常快,相当于确定哈希是否具有特定的键。文件 1 中的行是 F2 中的行当且仅当其哈希码是该集合的一个元素。
现在让我们修改这个方法以识别两个字符串可能具有相同的哈希码。我们将构造一个散列,而不是一个集合。
首先,我们需要一个辅助方法。
def a_repeat?(line, locs, f, loc)
locs.any? do |l|
pos = l
line == f.gets.chomp
end
pos = loc
end
这里:
-
line 是一个字符串;
-
locs 是文件 2 中的偏移量数组,它以具有给定哈希码的(chomped)行开头;
- f 是文件 2 的句柄,文件 2 已经打开读取;和
-
loc 是调用方法时文件 2 中的当前位置,需要在方法返回之前重新定位文件指针。
我们看到此方法确定(chomped)字符串 line 是否等于文件 2 中以 locs 给出的偏移量开始的任何行。
参见 [Enumerable#any?])(https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-any-3F)、IO#pos、IO#gets 和 IO#pos=。
我们现在可以构造哈希hash_codes。
hash_codes = {}
f = File.new(F2_NAME)
until f.eof?
loc = pos
line = f.gets.chomp
code = line.hash
if hash_codes.key?(code)
if a_repeat?(line, hash_codes[code], f, loc)
hash_codes[code] << loc
end
else
hash_codes[code] = [loc]
end
end
hash_codes
#=> {2098464159550983171=>[0], -1174471330590153942=>[16],
# -2185914657312873106=>[36], 4309024537421084150=>[55]}
注意以下几点。
[0, 16, 36, 55].each do |offset|
f.pos = offset
puts f.gets.chomp
end
展示
Now is the time
for all good coders
to come to the aid
of their fellow coders
如果文件 2 有一行从偏移量 67 开始,其哈希码为 -2185914657312873106,但不是字符串 "to come to the aid",则键 -2185914657312873106 的值为 [36, 67]。
请注意,文件 2 仍处于打开状态。
我们现在只是循环遍历文件 1 的每一行。
假设文件1的一行如下:
line = "to go to the mall"
然后我们计算
code = line.hash
#=> 1233397236348202523
作为hash_code.key?(code) #=> false,我们得出结论line不是文件2的行。现在假设文件1的行是
line = "to come to the aid"
我们计算
code = line.hash
#=> -2185914657312873106
因为hash_code.key?(code) #=> true,我们计算
locs = hash_code[code]
#=> [36]
这告诉我们文件 2 中有一行(或多行相同的行)具有哈希码 -2185914657312873106。但是,我们仍然必须验证这两行是否相同,因此对于locs、l 的每个元素,我们需要计算
f.pos = l
line == f.gets.chomp
这里是
f.pos = 36
line == f.gets.chomp
#=> true
告诉我们文件 1 中的那一行在文件 2 中。