他の列の最大値に基づいて列値を変更するようにテキストファイルを処理します。

他の列の最大値に基づいて列値を変更するようにテキストファイルを処理します。

修正したいファイルがあります。同じ問題のファイルが100個あります。入力ファイルは次のとおりです

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001
                
sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585
                
sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

上記のファイルでは、3番目の列の「合計」はルックアップテーブルであり、最大値は以下の各サンプルの行を超えてはいけません。

たとえば、「sample1」の最大値は1000ですが、3列目の「week1」と「week2」の最大値は「1001」です。私はこれが「week1とweek2」の数行でのみ発生し、常に最大値より1万大きいことがわかりました。 「week1」および「week2」行の出力は、最大値「1000」に更新する必要があります。以下の出力例

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59
                
sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000
                
sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584
                
sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125
                
sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

どのように進むべきかについての指示を提供してください。私は学びたい初心者プログラマーです。ご協力ありがとうございます

答え1

使用幸せ(以前のPerl_6)

~$ raku -e 'my @a = slurp.split("\n\n", 2);  print @a[0] ~ "\n\n"; 
            my %h;  for @a.[0].lines() { \%h.push: .words.[0,4] }; 
            for @a[1].lines {
                S/^ (\S+)(.* \s)(\S+) $/{"$0$1"}{ %h{$0} < $2 ?? "%h{$0}" !! "$2" }/.put };'   file.txt

RakuはPerlファミリーのプログラミング言語なので、構文は間違いなく「Perlに似ています」。上記では、slurpファイルを一度にメモリに入れ、2最初の段落の後にファイルをいくつかの部分に分割します。このデータは@a配列に保存されます。基準値()を含む最初の部分は@a[0]すぐに編集されますprint

%h次に、ハッシュ値を宣言します。 ...()を@a[0]使用して上のfor要約段落を繰り返しますlines。ここで、各行はスペースで区切られた行に分割され、最初wordsの/5番目の列は.[0,4]参照キー/値のペアとしてハッシュにpush追加されます。%h

ファイルの残りの部分()は@a[1]次のように繰り返されます。これは、ブロックの各行を分析/修正できることを意味します。変更された文字列を返すために、Rakuの非破壊置換イディオムを使用して、入力を最初の(キー)列、中間列、および最後の(値)列に分割します。forlinesS///$0$1$2

交換ではそのまま{"$0$1"}印刷します。ただし、最後の列の場合は、Rakuの三項演算子を使用して中括弧内でコードを実行できます。テスト ?? 本物 !! 間違ったこれより小さい場合は%h{$0}key関連項目)を返し、それ以外の場合は元の値()を返します。value$2$2

入力例:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1001
sample1 .   week2   50  1001

sample2 .   year    1   5584
sample2 .   week1   20  5585
sample2 .   week2   100 5585

sample3 .   year    1   8125
sample3 .   week1   55  8126
sample3 .   week2   100 8126

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

出力例:

sample1 100A    total   1   1000
sample2 100A    total   1   5584
sample3 100A    total   1   8125
sample4 100A    total   1   59

sample1 .   year    1   1000
sample1 .   week1   20  1000
sample1 .   week2   50  1000

sample2 .   year    1   5584
sample2 .   week1   20  5584
sample2 .   week2   100 5584

sample3 .   year    1   8125
sample3 .   week1   55  8125
sample3 .   week2   100 8125

sample4 .   year    1   59
sample4 .   week1   10  59
sample4 .   week2   8   59

最後に、中間データ構造を見ることが役に立つことが多いので、%hハッシュは次のようになります(used .say for %h.sort;)。

sample1 => 1000
sample2 => 5584
sample3 => 8125
sample4 => 59

https://docs.raku.org/syntax/S%2F%2F%2F%20Non-destructive%20replacement
https://docs.raku.org/言語/operators#infix_??_!
https://docs.raku.org/言語/regexes
https://raku.org

答え2

簡単なAwkドア:

awk -v OFS='\t' '$3 == "total" {maxval[$1] = $5} $1 in maxval && $5 > maxval[$1] {$5 = maxval[$1]} {print}' input.txt

いくつかの改行を追加しました。

awk -v OFS='\t' '
  $3 == "total" {
    maxval[$1] = $5
  }
  $1 in maxval && $5 > maxval[$1] {
    $5 = maxval[$1]
  }
  {print}' input.txt

説明する:

まず、入力ファイルの変数間隔に基づいて、元のテキストはタブ区切りのテキストであると仮定します。

デフォルトでは、Awkは隣接するタブまたはスペースの数に応じて別々のフィールドに解析します。このファイルには大丈夫です。

しかし、私たちは出力をきちんと整列させることを望み、デフォルトでいくつかのフィールド値を変更すると、Awkはその行のすべてのフィールド区切り文字を単一のスペースに変換します。したがって、出力フィールド区切り記号(OFS)をタブと同じに設定し、-v変数を設定するフラグを使用します。

3番目のフィールドが文字列 "total"の行の場合、最大値を連想配列(最もよく知られているプログラミング言語に従って「ハッシュ」とも呼ばれる)に格納します。

行の最初のフィールドが連想配列に存在し、5番目のフィールドが大きいそのキーの最大値として、配列に格納されている値よりも現在の行の5番目のフィールドを変更します。

次に、変更するかどうかに関係なく現在の行を印刷します。

提供された入力への出力:

sample1 100A    total   1       1000
sample2 100A    total   1       5584
sample3 100A    total   1       8125
sample4 100A    total   1       59

sample1 .       year    1       1000
sample1 .       week1   20      1000
sample1 .       week2   50      1000

sample2 .       year    1       5584
sample2 .       week1   20      5584
sample2 .       week2   100     5584

sample3 .       year    1       8125
sample3 .       week1   55      8125
sample3 .       week2   100     8125

sample4 .       year    1       59
sample4 .       week1   10      59
sample4 .       week2   8       59

関連情報