源文件:
- 标题开头为
H
- 预告片开头为
T
- 记录以 R 开头
- 分隔符为
|~^
输入文件样本
以R开头的输入记录在原始源文件中有多个字段;这里我只说了示例中的5个字段。
预告片记录第三列是记录数,第五列是金额列(第三列或记录行)的总和
分割后,预告片应添加到新文件中,格式如下,包含计数和总和列。
以 R 开头的 INPUT 记录将不遵循日期顺序。例如:第一个记录的记录为 2019-03-05,最后一条记录也是同一日期。
笔记:
以 R 开头的 INPUT 记录将在多列中包含日期字段,因此请考虑拆分第三个日期字段
另外,请忽略日期字段中的时间戳;您可以只考虑日期并仅根据日期执行拆分。理想情况下,第三列中所有相同日期的交易应移至新文件,并添加包含总和和计数的标题/尾部。 ****编辑****** 我的问题仍然是一样的,但如果金额字段是非常大的数字(考虑金额字段数据类型是 Number(31,5),其中小数点最多可达 5 点,并非每次都会是 (31,5) 如果有任何带有 5 位小数的金额,则该值将最多为 5 位小数)
输入文件:
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^8|~^xxx|~^123670130.37256
预期产出
文件 1:应另存为20190305.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4|~^xxx|~^107707.068
文件 2:应另存为20190306.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4|~^xxx|~^123562423.30456
答案1
通过您的最后一次编辑,您改变了整个问题。
现在,对于每一行,时间戳必须转换为文件名。
即从2019-03-06T12:33:52.27
到20190306
。仅此一项就需要相当多的字符串处理,这对于任何语言来说都不是很快。
这一小部分可以在 awk 中完成:
awk 'BEGIN{FS="\\|~\\^";OFS="|~^"}
$1=="R"{
t=gensub(/-/, "","g",$3)
s=gensub(/T.*/,"",1,t);
$3=s
}
1
' "file" >"file.adj"
然后,仍然存在根据时间戳日期的日期划分文件的(您最初的问题)。所需的最少更改列表如下:
- 将输入的每一行复制到特定的(由 $3 给出的)文件。
- 完成后,还要计算行数(对于每个文件)
- 并对 field 上的值求和
4
。 - 处理完所有输入行后,将尾部打印到每个文件。
整个过程可以在 awk 中完成,如下所示:
awk 'BEGIN { FS="\\|~\\^"; OFS="|~^" }
$1=="H"{ header=$0; hdr=$2 }
$1=="R"{
t=gensub(/-/, "","g",$3)
file=gensub(/T.*/,"",1,t);
sum[file]+=$4
if(count[file]==0){ print header >file }
count[file]++
print $0 >>file
}
END {
for( i in sum ){
print "T",hdr,count[i],"xxx",sum[i] >> i;
close(i)
}
}
' "file"
使用 Perl 重复源文件 100 万次,处理整个文件仅需 49.32 秒。内存使用最少(只需每天的总和和计数需要保留在内存中)。这对我来说似乎相当快。
答案2
这是一个awk
解决方案:
awk -F'\\|~\\^' '{
if($1=="H"){
head=$0
}
else if($1=="T"){
foot=$1"|~^"$2
foot4=$4
}
else{
date=$3;
sub("T.*","", date);
data[date][NR]=$0;
sum[date]+=$4;
num[date]++
}
}
END{
for(date in data){
file=date".txt";
gsub("-","",file);
print head > file;
for(line in data[date]){
print data[date][line] > file
}
printf "%s|~^%.3f|~^%s|~^%.3f\n", foot, num[date],
foot4, sum[date] > file
}
}' file
当运行示例数据时,会产生:
$ cat 20190305.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4.000|~^xxx|~^107707.068
$ cat 20190306.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4.000|~^xxx|~^123562423.305
另外,由于您似乎认为 awk 很慢,所以我在一个大文件上测试了它。为了创建我的测试文件,我运行了以下命令:
perl -e '@d=<>; print $d[0]; $str=join("",@d[1..$#d-1]); print $str x 3500000; print $d[$#d]' file > bigFile
这将创建一个包含 28000002 行的 1.9G 文件,其中第一行是原始文件的页眉,最后一行是原始文件的页脚,行与行之间是原始文件内容的 350 万次重复。然后我在这个文件上运行 awk(请注意,我有足够的 RAM 来执行此操作,您将需要至少 618M 的可用 RAM):
$ time awk -F'\\|~\\^' '{ if($1=="H"){head=$0} else if($1=="T"){foot=$1"|~^"$2; foot4=$4;} else{date=$3; sub("T.*","", date);data[date][NR]=$0;sum[date]+=$4;num[date]++;} }END{for(date in data){file=date;gsub("-","",file); sub("T.*",".txt",file); print head > file; for(line in data[date]){print data[date][line] > file} printf "%s|~^%s|~^%s|~^%s\n", foot, num[date], foot4, sum[date] > file } }' bigFile
real 2m8.603s
user 2m0.610s
sys 0m6.795s
因此,2 分钟即可处理 28,000,002 行 1.9G 的数据。这相当快(虽然艾萨克的解决方案在 1m 30 时速度更快,并且使用更少的内存,因此 UI 建议您使用它)。我绝对可以保证你永远不会用 shellfor
循环这么快地得到它。就此而言,也不能使用 R for 循环。