
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
を読み、各行はスペースで区切られた行に分割されますwords
(map
これは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
%agg1
key
values
key
value
%agg1
#Add this statement:
.say for %agg1.sort;
#Returns:
New => [762 8622]
Text => [520 450]
Value => [672 872]
%agg1
%sum1
その後、対応するハッシュが再度繰り返され、個人を合理的な方法で合計するハッシュが生成される。最後に、データはタブで区切られて出力され(引用符で囲まれたタブはコード内の二重引用符の必要性が減ります)、チルダを介して文字列連結が実行されます。values
key
~qb[\t]~
\t
~
https://andrewshitov.com/2020/03/16/a- Couple-of-syntax-sweets-in-raku/
https://youtu.be/wViVLytlwb8
https://raku.org