Perlまたはbashでのテキストファイルの集約とグループ化

Perlまたはbashでのテキストファイルの集約とグループ化

;次の形式(4列、区切り)の大きなテキストファイル(5m行)があります。

文字列1;文字列3;

これ最初の3つの文字列(SHA1)とい​​う単一のIDを形成します。アプリケーションID(それでこれを簡単にすることができます:)appId; userId。 2番目の列(string2または2番目の部分アプリケーションID)自体は、カンマで区切られたいくつかの部分で構成できます,。ファイルがソートされました。

次のように、各アプリケーションのユーザーリストを取得したいと思います。

入力する文書:

app1, user1
app1, user2
app1, user3
app2, user1

出力文書:

app1: user1, user2, user3
app2: user1

「本物」の一部入力する文書:

44a934ca4052b34e70f9cb03f3399c6f065becd0;bf038823f9633d25034220b9f10b68dd8c16d867;309;8ead5b3e0af5b948a6b09916bd271f18fe2678aa
44a934ca4052b34e70f9cb03f3399c6f065becd0;bf038823f9633d25034220b9f10b68dd8c16d867;309;a21245497cd0520818f8b14d6e405040f2fa8bc0
5c3eb56d91a77d6ee5217009732ff421e378f298;200000000000000001000000200000,6fd299187a5c347fe7eaab516aca72295faac2ad,e25ba62bbd53a72beb39619f309a06386dd381d035de372c85d70176c339d6f4;16;337556fc485cd094684a72ed01536030bdfae5bb
5c3eb56d91a77d6ee5217009732ff421e378f298;200000000000000001000000200000,6fd299187a5c347fe7eaab516aca72295faac2ad,e25ba62bbd53a72beb39619f309a06386dd381d035de372c85d70176c339d6f4;16;382f3aaa9a0347d3af9b35642d09421f9221ef7d
5c3eb56d91a77d6ee5217009732ff421e378f298;200000000000000001000000200000,6fd299187a5c347fe7eaab516aca72295faac2ad,e25ba62bbd53a72beb39619f309a06386dd381d035de372c85d70176c339d6f4;16;396529e08c6f8a98a327ee28c38baaf5e7846d14

「本物」出力ファイルは次のようにする必要があります。

44a934ca4052b34e70f9cb03f3399c6f065becd0;bf038823f9633d25034220b9f10b68dd8c16d867;309:8ead5b3e0af5b948a6b09916bd271f18fe2678aa, a21245497cd0520818f8b14d6e405040f2fa8bc0
5c3eb56d91a77d6ee5217009732ff421e378f298;200000000000000001000000200000,6fd299187a5c347fe7eaab516aca72295faac2ad,e25ba62bbd53a72beb39619f309a06386dd381d035de372c85d70176c339d6f4;16:337556fc485cd094684a72ed01536030bdfae5bb, 382f3aaa9a0347d3af9b35642d09421f9221ef7d, 396529e08c6f8a98a327ee28c38baaf5e7846d14

どうすればいいですか?


編集する:また、各アプリケーションには何千人ものユーザーがいる可能性がありますが、キューはどのくらい長くなりますか?行の長さに制限がありますか?

ベストアンサー1

パールから

perl -F';' -lane 'push @{$h{join ";",@F[0..2]}},$F[3];
                  END{
                    for(sort keys %h){
                        print "$_: ". join ",",@{$h{$_}};
                    }
                  }' your_file

連想配列を使用して同様のことを行うことができなければなりませawkんが、私はこれに精通していないので、awk実際のコードに貢献することはできません。

説明する

以下は、「魔法」をできるだけ少なく使用する上記のコードの拡張バージョンです。

open($FH,"<","your_file");
while($line=<$FH>){ # For each line in the file (accomplished by -n)
    chomp $line; # Remove the newline at the end (done by -l)
    # The ; is set by -F and storing the split in @F done by -a
    @F = split /;/,$line # Split the line into fields on ;
    $app_id = join ";",@F[0..2]; # AppID is the first 3 fields
    push @{$h{$app_id}},$F[3]; # The 4th field is added onto the hash
} # The whole file has been read at this point.
foreach $key (sort keys %h){ # Sort the hash by AppID
     print "$key: " . join ",",@{h{$key}}."\n"; # Print the array values
     # The newline ("\n") added at the end is also done by -l
}

これで、pushこの文だけを詳しく説明できます。

  • push通常、配列変数に要素を追加するために使用されます。たとえば、

    push @a,$x
    

    変数の内容を$x配列に追加します@a

  • ファイルを1行ずつ読み込むループがハッシュテーブル(%h)を埋めています。ハッシュのキーはAppIDであり、各キーに対応する値はそのAppIDに関連付けられているすべてのユーザーIDを含む配列です。これは匿名配列です(名前なし)。 Perlは配列参照として実装されています(Cポインタとやや似ています)。%hAppID に対応する値は$app_idで表されるため、Perl$h{$app_id}配列 sigial( @) を追加するとハッシュ値を配列として処理し (配列参照逆参照)、現在のユーザー ID をここにプッシュします。

  • 「Perlish」のように感じることができるもう1つの選択肢は、4番目のフィールドを現在の値にリンクすることです。

    while(...) { ... $h{$app_id} = $h{$app_id} . ",$F[3]" }
    foreach $key (sort keys %h) { print "$_: $h{$_}" }
    

    Perlは.文字列連結演算子です。

説明されたコードでは、perl -e '...'構文の強調表示がコードに到達し、読みやすくするためにラッパーを省略しました。

おすすめ記事