日付に基づいてファイルを分割し、合計と金額を含む予告編を追加します。

日付に基づいてファイルを分割し、合計と金額を含む予告編を追加します。

ソースファイル:

  • タイトルは次から始まります。H
  • 予告編は次のように始まります。T
  • R で始まるレコード
  • 区切り記号は次のとおりです。|~^

入力ファイルのサンプル

  • R で始まる入力レコードには、ソースソースファイルに複数のフィールドがあります。ここでは、例では5つのフィールドしか言及していません。

  • トレーラーレコードの3番目の列はレコード数で、5番目の列は金額列(レコードの3番目の列または行)の合計です。

  • 分割後のトレーラーは、数と合計の列を含む次の形式で新しいファイルに追加する必要があります。

  • R で始まる INPUT レコードは日付順に従わない。たとえば、最初のレコードは2019-03-05として記録され、最後のレコードも同じ日付です。

メモ:

  • R で始まる INPUT レコードには複数の列の日付フィールドが含まれるため、3 番目の日付フィールドを分割することをお勧めします。

  • またお願いします日付フィールドのタイムスタンプを無視;日付のみを考慮し、日付のみに基づいて分割を実行できます。理想的には、3列目の同じ日付のすべての取引を新しいファイルに移動し、合計と数が追加されたヘッダー/トレーラーに移動する必要があります。 ****編集********私の質問はまだ同じですが、金額フィールドが非常に大きい数値である場合(金額フィールドデータ型は小数点が最大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として提供)にコピーします。
  • 完了したら(各ファイルに対して)行数を計算します。
  • そしてフィールドの値を合計します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秒で処理されました。最小メモリ使用量(1日の合計と数をメモリに保持するだけです)これは私にとってかなり速いようです。

答え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

したがって、1.9Gデータの28,000,002行を2分で処理できます。これはかなり速いです(たとえアイザックの解決策1m 30では、より高速でメモリの使用量が少ないため、UIでの使用をお勧めします。forシェルループでは決してこのように早く得られないだろうと大胆にすることができます。その問題については、R for ループも使用できません。

関連情報