大家好:)我真的很困惑一个任务: - /
每天有一个2000000到4000000个字符串的文件,其中包含一行一行的15个符号,如下所示:
850025000010145
401115000010152
400025000010166
770025555010152
512498004158752
从今年年初开始,您会有相应数量的此类文件。因此,我必须将今天文件的每一行与今年年初的所有先前文件进行比较,并仅返回所有已检查文件中之前从未遇到的数字。
我应该使用哪种语言和算法?如何实现呢?
答案 0 :(得分:3)
您应该能够执行此操作,而无需编写除简单脚本之外的任何代码(即bash,Windows批处理,Powershell等)。有一些标准工具可以快速完成这类工作。
首先,您有一些包含200万到400万个数字的文件。使用所有这些文件很困难,因此您要做的第一件事就是创建一个已排序的组合文件。这种简单的方法是将所有文件连接成一个文件,对其进行排序,并删除重复项。例如,使用GNU / Linux cat
和sort
命令:
cat file1 file2 file3 file4 > combined
sort -u combined > combined_sort
(-u
删除重复项)
该方法的问题在于您最终会对非常大的文件进行排序。图4百万行,每行15个字符,加上换行符,几乎100天的文件,并且您正在使用7千兆字节。一整年的数据将是25千兆字节。这需要很长时间。
因此,对每个单独的文件进行排序,然后将它们合并:
sort -u file1 >file1_sort
sort -u file2 >file2_sort
...
sort -m -u file1 file2 file3 > combined_sorted
-m
开关合并已经排序的文件。
现在你拥有的是到目前为止你所见过的所有标识符的排序列表。您想要将今天的文件与之进行比较。首先,排序今天的文件:
sort -u today >today_sort
现在,您可以比较文件并仅输出今天文件的唯一文件:
comm -2 -3 today_sort combined_sort
-2
表示仅限制在第二个文件中出现的行,而-3
表示要抑制两个文件共有的行。所以你得到的是today_sort
中不存在combined_sort
中的行。
现在,如果您每天都要这样做,那么您需要从comm
命令获取输出并将其与combined_sort
合并,以便您可以使用该组合文件明天。这可以防止您每天必须重建combined_sort
文件。所以:
comm -2 -3 today_sort combined_sort > new_values
然后:
sort -m combined_sort new_values > combined_sort_new
您可能希望使用日期为文件命名,因此您需要combined_sort_20140401
和combined_sort_20140402
等。
因此,如果您在年初开始并希望每天都这样做,那么您的脚本应该是这样的:
sort -u $todays_file > todays_sorted_file
comm -2 -3 todays_sorted_file $old_combined_sort > todays_uniques
sort -m $old_combined_sort todays_sorted_file > $new_combined_sort
$todays_file
,$old_combined_sort
和$new_combined_sort
是您在命令行上传递的参数。因此,如果脚本被调用"每天":
daily todays_file.txt all_values_20140101 all_values_20140102
答案 1 :(得分:0)
如果你必须用手解决问题:
- 将字符串转换为64位整数。这节省了空间(2x到4x)并加快了速度 - 计算计算
- 排序当前整数文件
- 将当前文件与旧数据文件(已排序)合并,选择新数字
合并步骤可能看起来像MergeSort的合并步骤。 您可以将数字范围存储在单独的文件中,以避免超大文件大小。
P.S。我想建议使用位图,但它的大小约为125 TB
答案 2 :(得分:0)
一种解决方案可能是基于之前的n-1
文件构建prefix tree(假设今天创建了n
文件)。最耗时的构建过程只需要完成一次。构建前缀树后,可以将其另存为文件(google用于此主题)。
运行程序以检查新文件:
try(BufferedReader br = new BufferedReader(new FileReader("new_file.txt"))) {
String line = br.readLine();
while (line != null) {
if(!tree.contains(line)){
counter++;
}else{
tree.insert(line);
}
line = br.readLine();
}
}
因此,每天运行此“伪”代码,获取唯一查询并更新树。
contains
需要O(m)时间,其中m是字符数
insert
也花费O(m)时间
我建议使用Java。