awkを使用して同様の行にデータを追加する

awkを使用して同様の行にデータを追加する

私のファイルのデータは次のとおりです。

field11|field12|field13
field11|field12|field23
field11|field32|field33
field41|field42|field43
field41|field52|field43
field41|field62|field63

ご覧のとおり、私は2つのIDを持っており、field11field41のようにそのIDが一度だけ表示されるようにしたいと思います。

field11|{'field12','field32'}|field13
field41|{'field42','field52','field62'}|field43

私は3番目のフィールドがそのIDの最初の項目と同じであることを望みます。各id($ 1)は$ 3が異なりますが、最初または最初と2番目のフィールドは同じままです。ただし、そのIDの最初の行の内容を印刷する必要があります。例に示すように、field23の代わりにfield13を印刷します。

私はawkこれを/として達成しようとしていますsed。私はシェルの基本ループを使ってこれを達成するソリューションを知っています。ただし、awkこれは他の同様のツールで行う必要があります。

答え1

やや長い(しかし理解しやすい)awk解決策:

BEGIN       { FS = OFS = "|" }

function output() {
    if (FNR == 1) return
    data = ""
    for (i in col2) {
        qi   = sprintf("'%s'", i);
        data = (data == "" ? qi : data "," qi)
    }
    print col1, sprintf("{%s}", data), col3
}

$1 == col1 && !($2 in col2) { col2[$2] }

$1 != col1    {
    output()
    col1 = $1; col3 = $3
    delete col2; col2[$2]
}

END { output() }

このBEGINブロックは、単に入力と出力フィールドの区切り記号を|

この関数は、(最初​​の列のID)、(2番目の列の一意のデータ配列)、および(3番目の列の対応する特定のIDの最初のデータ項目)から収集されたデータを取得してoutput()出力します。のキーを繰り返して個別に引用し、間にカンマを使用して文字列変数に追加します。次に、(中括弧内)とを印刷します。col1col2col3col2datacol1datacol3

その特定のIDに対して以前に一度も見たことがなかった2番目の列のエントリが見つかった場合は、次のブロックが実行されます。 2番目の列をのキーとして追加するだけですcol2

最初の列で新しいIDが見つかると、次のブロックが実行されます。収集した変数を呼び出してoutput()リセットして、新しいIDのデータ収集を開始します。

ENDブロックはoutput()最後のIDの出力データを呼び出します。

プログラムはファイル全体を一度にメモリに保存しようとはしませんが、データを最初の列でソートする必要があります。

提供されたデータに対して実行します。

$ awk -f script.awk file
field11|{'field12','field32'}|field13
field41|{'field42','field62','field52'}|field43

答え2

Perlのいくつかの粗い部分:

perl -F'\|' -lane '
    $f2{ $F[0] }{ $F[1] } = 1;
    $f3{ $F[0] } = $F[2] if not exists $f3{ $F[0] }; 
  } END {
    for $key (sort keys %f2) {
        printf "%s|{%s}|%s\n", 
            $key, 
            join(",", map {chr(39) . $_ . chr(39)} sort keys %{$f2{$key}}), 
            $f3{$key};
    }
' file

最初の2行は連想配列を使用してデータを蓄積します。
その後、END ブロックはデータ、書式設定、印刷を繰り返します。

関連情報