
ソースファイル:
- タイトルは次から始まります。
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.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として提供)にコピーします。
- 完了したら(各ファイルに対して)行数を計算します。
- そしてフィールドの値を合計します
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 ループも使用できません。