【发布时间】:2016-04-01 07:15:38
【问题描述】:
我在两个大文件中有一些信息。
其中之一(file1.txt,大约有 400 万行)包含所有对象名称(唯一的)和类型。
而另一个(file2.txt,有大约 200 万行)一些对象名称(它们可以重复)和分配给它们的一些值。
所以,我在file1.txt 中有类似下面的内容:
objName1 objType1
objName2 objType2
objName3 objType3
...
在file2.txt 我有:
objName3 val3_1
objName3 val3_2
objName4 val4
...
对于file2.txt 中的所有对象,我需要在单个文件中输出对象名称、它们的类型和分配给它们的值,如下所示:
objType3 val3_1 "objName3"
objType3 val3_2 "objName3"
objType4 val4 "objName4"
...
以前file2.txt 中的对象名称应该是唯一的,所以我实现了一些解决方案,我从两个文件中读取所有数据,将它们保存到 Tcl 数组,然后遍历更大的数组并检查具有相同名称的对象是否存在于较小的数组中,如果存在,则将我需要的信息写入单独的文件。但这运行时间太长(> 10 小时且尚未完成)。
我该如何改进我的解决方案,或者有其他方法可以做到这一点?
编辑:
实际上我没有file1.txt,我正在通过某种程序找到该数据并将其写入 Tcl 数组。我正在运行一些程序来获取对象类型并将它们保存到 Tcl 数组,然后,我正在读取 file2.txt 并将数据保存到 Tcl 数组,然后我正在迭代第一个数组中的项目,如果对象名称匹配第二个(对象值)数组中的某个对象,我正在将信息写入输出文件并从第二个数组中删除该元素。这是我正在运行的一段代码:
set outFileName "output.txt"
if [catch {open $outFileName "w"} fid ] {
puts "ERROR: Failed to open file '$outFileName', no write permission"
exit 1
}
# get object types
set TIME_start [clock clicks -milliseconds]
array set objTypeMap [list]
# here is some proc that fills up objTypeMap
set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start]
puts "Info: Object types are found. Elapsed time $TIME_taken"
# read file2.txt
set TIME_start [clock clicks -milliseconds]
set file2 [lindex $argv 5]
if [catch { set fp [open $file2 r] } errMsg] {
puts "ERROR: Failed to open file '$file2' for reading"
exit 1
}
set objValData [read $fp]
close $fp
# tcl list containing lines of file2.txt
set objValData [split $objValData "\n"]
# remove last empty line
set objValData [lreplace $objValData end end]
array set objValMap [list]
foreach item $objValData {
set objName [string range $item 0 [expr {[string first " " $item] - 1}] ]
set objValue [string range $item [expr {[string first " " $item] + 1}] end ]
set objValMap($instName) $objValue
}
# clear objValData
unset objValData
set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start]
puts "Info: Object value data is read and processed. Elapsed time $TIME_taken"
# write to file
set TIME_start [clock clicks -milliseconds]
foreach { objName objType } [array get objTypeMap] {
if { [array size objValMap] eq 0 } {
break
}
if { [info exists objValMap($objName)] } {
set objValue $objValMap($objName)
puts $fid "$objType $objValue \"$objName\""
unset objValMap($objName)
}
}
if { [array size objValMap] neq 0 } {
foreach { objName objVal } [array get objValMap] {
puts "WARNING: Can not find object $objName type, skipped..."
}
}
close $fid
set TIME_taken [expr [clock clicks -milliseconds] - $TIME_start]
puts "Info: Output is cretaed. Elapsed time $TIME_taken"
似乎最后一步(写入文件)有大约 8 * 10^12 次迭代要做,在合理的时间内完成是不现实的,因为我已经尝试做 8 * 10^12 次迭代在 for 循环中,只打印迭代索引,~850*10^6 次迭代花费了约 30 分钟(因此,整个循环将在约 11 小时内完成)。
所以,应该有另一种解决方案。
编辑:
似乎原因是 file2.txt 地图的一些不成功的散列,因为我试图在 file2.txt 中洗牌并在大约 3 分钟内得到结果。
【问题讨论】:
-
如果没有看到你运行的代码,就很难回答这个问题。
-
好的,我将通过添加一段代码来更新我的问题。
-
@Jackson,请在我的问题中查看更新。
-
10 小时有点长。我在 6 小时内处理了 3200 万行。不过,对于大文件,我不使用
read,而是使用while和gets一次获取一行(因此无需拆分,也不会在少数变量中消耗大量内存) . -
您应该考虑将该数据导入 sqlite 数据库并使用 sql 创建结果数据。
标签: file join tcl large-data