web-dev-qa-db-ja.com

awkを使用して、多対1の関係を持つ2つの列に基づいてデータをフィルタリングする必要があります

|で区切られた50の列と100Kの行を持つ大きなファイルがあります。これで、$ 2(列2)には複数のタイプの$ 1(列1)値があり、列2が繰り返されることを意味します。だから私はファイルをソートしました。以下の条件に基づいて結果ファイルを抽出/フィルタリングする必要があります。$ 1は列1、$ 2は列2です。

2ドルから1ドルの間に1対多の関係船があります

条件1:$ 2のタイプが両方とも$ 1の場合($ 2の$ 1の値が8000を超え、8000未満の場合)、指定された$ 2に対して$ 1 <8000である行全体を選択します(列2)

条件2:$ 2に$ 1> = 8000しかない場合は、指定された$ 2(列2)に対して$ 1が最小である行全体を選択します。例:ソースファイル次の例では、3種類の$ 2(1234,123&456)があります。これで、1234の列1に3種類の値($ 1)があり、8000よりも大きいことと小さいことを意味します。したがって、$ 1 <8000の値に対して完全な行を選択しました。

123と465の場合、列1の値は8000($ 1> 80000)よりも大きいため、(列8の値が高いことに基づいて)最新の行を選択しました。

サンプルファイル

  4000|1234||||||23
    5000|1234||||||40
    9000|1234||||||25
    10000|123|||||||21
    9000|123|||||||22
    22000|456|||||||27
    15000|456|||||||29

結果ファイルは次のようになります。

4000|1234||||||23
5000|1234||||||40

9000|123|||||||22

15000|456|||||||29

アドバイスを下さい。前もって感謝します。

1
api1411

試してみてください(uはあなたのファイルです)

_sort -n -t\| -k2 -k1 < u |
awk -F\| '$1 < 8000 { a[$2]++ ; print } 
          $1 >= 8000 { if ( !a[$2] && ( !e[$2] || e[$2]<$8 ))  {u[$2]=$0;e[$2]=$8;} ; } 
          END { for ( i in u ) print u[i] ;}'
_

与える

_4000|1234||||||23
5000|1234||||||40
15000|456||||||29
9000|123||||||22
_

どこ

  • _-t\|_と_-F\|_は、sortとawkに_|_を区切り文字として使用するように指示します
  • _-k2_ _-k1_:秒で並べ替え、次に最初のフィールド
  • ソート行の_|_は、行の最後の文字である必要があります
  • _$1 < 8000 { a[$2]++ ; print }_ 8000未満の場合は、行を印刷し、$ 2の値を覚えておいてください
  • _$1 >= 8000 { ... }_上記の場合、最高値を保存します
  • END { for ( i in u ) print u[i] ;}終了時に、すべての値をダンプします

  • 再ソートが必要になる場合があります。

  • 2行目の条件を簡略化できます(ifの条件を{}の外に置くことで)

  • テストの一部の行には9つのフィールドがあります。

コマンドは1行にすることができることに注意してください

_... | sort -n -t\| -k2 -k1  | awk -F\| '...'
_
3
Archemar