根据日期拆分文件,添加带有总和和金额计数的预告片

根据日期拆分文件,添加带有总和和金额计数的预告片

源文件:

  • 标题开头为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.2720190306。仅此一项就需要相当多的字符串处理,这对于任何语言来说都不是很快。

这一小部分可以在 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 循环。

相关内容