3列データファイルで、「キー」の発生回数と関連する「値」の合計を印刷します。

3列データファイルで、「キー」の発生回数と関連する「値」の合計を印刷します。

Redisダンプファイルを読み取るためにシェルを使用しています。

ダンプファイルには、次の3つの主な列があります。

Text:tags:name    682651    520
Text:tags:age     78262     450
Value:cache       77272     672
Value:cache:name  76258     872
New:specific      77628     762
New:test          76628     8622

予想出力:

Key     Count     Sum
Text:*  2         970
Value:* 2         1544
New:*   2         9384

文字列(キー)で開始/中間/終了できるサブ文字列に基づいて列を確認できるので、上記の期待を得たいと思います。

答え1

次のawkプログラムがこれを行います。

awk '{split($1,f,/:/);count[f[1]]++;sum[f[1]]+=$3}
     END{printf "Key\tCount\tSum\n"; for (k in count) {printf "%s:*\t%d\t%d\n",k,count[k],sum[k]}}' dump.txt
  • これは最初に列1のキーをコンポーネント:に分割し、それを配列に保存しますf。最初の項目(f[1])は、すべての追加処理のための関連キーと見なされます。
  • 発生回数は、countキーをf[1]配列インデックスとして使用して連想配列に格納されます。キーが見つかるたびに1ずつ増加します。
  • 列3の値の合計は類似配列に格納されますsum
  • 最後に、プログラムはヘッダー行を印刷し、配列に見つかったすべての配列インデックスを繰り返して、配列countインデックス(=キー)、発生数、および合計値を印刷します。

キーが印刷される順序は、格納されたawk配列の内部ロジックによって定義されます。 GNU Awkがある場合は、セクションの属性を設定して巡回順序を定義できますPROCINFO["sorted_in"]BEGIN例えば

BEGIN{PROCINFO["sorted_in"]="@ind_str_asc"}

awk「キー」に基づいて項目がアルファベット順に昇順で印刷されます。

答え2

最初のフィールド以降のすべての内容が次に:置き換えられるように、最初のフィールドを変更することから始めます*

awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' file

このコマンドは、拡張正規表現の最初の項目をリテラル文字列に置き換えて、スペースで区切られたawk最初のフィールドを変更します。データに応じてタブ区切りのデータが出力されます。:.*:*

Text:*  682651  520
Text:*  78262   450
Value:* 77272   672
Value:* 76258   872
New:*   77628   762
New:*   76628   8622

その後、各グループの縮小行数を計算し、3番目のフィールドを合計しながらタブ区切りの最初のフィールドにグループ化できます。 1つの方法はGNUを使用することですdatamash

awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' file |
datamash groupby 1 count 1 sum 3

awk元の入力がソートされていない場合は、データが渡されるか、そのsortオプションdatamash-s使用されます。

これにより、以下が出力されます(タブで区切られます)。

Text:*  2       970
Value:* 2       1544
New:*   2       9384

ヘッダーを出力するには、まず次のように呼び出します。

printf '%s\t%s\t%s\n' 'Key' 'Count' 'Sum'

完全なのは、fileいくつかの新しいファイルを読み書きすることですoutput

{
    printf '%s\t%s\t%s\n' 'Key' 'Count' 'Sum'
    awk -v OFS='\t' '{ sub(":.*", ":*", $1) }; 1' |
    datamash groupby 1 count 1 sum 3
} <file >output

答え3

$ awk -F'[:[:space:]]+' '
    { cnt[$1]++; sum[$1]+=$NF }
    END {
        print "Key", "Count", "Sum"
        for (key in cnt) {
            print key":*", cnt[key], sum[key]
        }
    }
' file | column -t
Key      Count  Sum
Value:*  2      1544
Text:*   2      970
New:*    2      9384

答え4

使用幸せ(以前のPerl_6)

~$ raku -e 'my (@k, @v); given lines.map(*.words).list {  \
            @k = .map(*.[0].split(":").[0]); @v = .map(*.[2]) };  \
            my %count1 = Bag(@k); my %agg1.=append: [Z=>] @k, @v;  \
            my %sum1; for %agg1 { %sum1.append: $_.key => [+] $_.value };  \
            for ([Z] %count1.sort, %sum1.sort) {  \
            say .[0].key ~qb[\t]~ .[0].value ~qb[\t]~ .[1].value};' file

入力例:

Text:tags:name    682651    520
Text:tags:age     78262     450
Value:cache       77272     672
Value:cache:name  76258     872
New:specific      77628     762
New:test          76628     8622

出力例:

New     2   9384
Text    2   970
Value   2   1544

このソリューションは、すべてのPerlファミリー言語に存在するハッシュ機能を利用しており、特にRakuで書かれています。

つまり、linesを読み、各行はスペースで区切られた行に分割されますwordsmapこれはRakuに「すべての」行要素内で作業するように指示することです)。データは、@kコロンの後の最初の文字列要素を含む配列と3番目の列のみを含む配列(0インデックス= 2)に格納されます。この時点で、配列は次のようになります。split@v

#Add this statement:
.say for @k, @v;

#Returns:
[Text Text Value Value New New]
[520 450 672 872 762 8622]

Rakuには、Bag()各キーの発生回数(個数)を提供する機能が組み込まれています(行使用my %count1 = Bag(@k);)。

これからおよび列を「圧縮」して、一緒にペアを形成してハッシュに入れる集計ハッシュが%agg1生成されます。もちろん、ハッシュの1つの属性は、各ハッシュが一意であるということです。したがって、同じハッシュに関連付けられた配列要素は、各キーを構成する配列要素に配置されます。この時点で、ハッシュは次のようになります。@k@v=>append%agg1keyvalueskeyvalue%agg1

#Add this statement:
.say for %agg1.sort;

#Returns:
New => [762 8622]
Text => [520 450]
Value => [672 872]

%agg1%sum1その後、対応するハッシュが再度繰り返され、個人を合理的な方法で合計するハッシュが生成される。最後に、データはタブで区切られて出力され(引用符で囲まれたタブはコード内の二重引用符の必要性が減ります)、チルダを介して文字列連結が実行されます。valueskey~qb[\t]~\t~

https://andrewshitov.com/2020/03/16/a- Couple-of-syntax-sweets-in-raku/
https://youtu.be/wViVLytlwb8
https://raku.org

関連情報