在两个大型列表之间使用多进程查找更改

wnrlj8wa  于 2021-09-29  发布在  Java
关注(0)|答案(1)|浏览(302)

我试图比较两个巨大的列表,找出哪些行不在第二个列表中。
例如:
清单1:a、b、c、d
清单2:a g h d
结果:b c
b c在列表1中,但不在列表2中。
list1的大小是60gb的行。list2的大小是76gb的行。
尝试加载列表时,由于内存不足,进程将被终止。
我尝试过使用Pandas,但这需要很长时间,我想添加一些多处理来加快速度,但我无法实现。这是我的密码:

import pandas as pd

for chunk in pd.read_csv("/folder/list1",chunksize=1000,header=None):
    for ind in chunk.index:
        flag =0
        for chunk1 in pd.read_csv("/folder/list2",chunksize=1000,header=None):
            for ind1 in chunk1.index:
                if chunk[0][ind] == chunk1[0][ind1]:
                    flag = 1
                    break
    if flag == 0:
            with open(f"result", 'a+') as file:
            file.write(chunk[0][ind] + '\n')
mftmpeh8

mftmpeh81#

下面是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的句柄,该文件已打开读取;和 loc 调用方法时文件2中的当前位置,需要在方法返回之前重新定位文件指针。
我们看到此方法确定(chomped)字符串 line 等于文件2中以给定偏移量开始的任何行 locs .
请参阅[可枚举#任何?])(https://ruby-doc.org/core-2.7.0/enumerable.html#method-i-any-3f),io#pos,io#get和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的每一行(chomped)。
假设文件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中。

相关问题