テキストファイル内の行にわたる列数の頻度を印刷する

テキストファイル内の行にわたる列数の頻度を印刷する

次のようなファイルがあります:

1
2 4 5 6 
20
22
24 26 27 
29 30 31 32 34 40 50 56 58
234 235 270 500
1234 1235 1236 1237
2300

1 列の行が 4 行、4 列の行が 3 行、3 列の行が 1 行、9 列の行が 1 行あることを示す出力が欲しいです。つまり、出力は次のようになります: 行 ( 列)

4 (1)
1 (3)
3 (4)
1 (9)

実際のデータが膨大であることを考慮すると、何か提案はありますか? 一方、出力では、最後の行に列の最大数 (ここでは 9) を表示し、最初の行に列の最小数を表示したいと考えています。

答え1

GNU awk の最新バージョン (> 4.0) をお持ちの場合:

gawk '
  {a[NF]++} 
  END {
    PROCINFO["sorted_in"]="@ind_num_asc"; 
    for (i in a) printf "%d (%d)\n", a[i], i;
  }' file
4 (1)
1 (3)
3 (4)
1 (9)

答え2

驚いて見るアプローチ(asorti関数を使用):

awk '{a[NF]++}END{ asorti(a,b); for(i in b) printf("%d (%d)\n",a[b[i]],b[i]) }' file

出力:

4 (1)
1 (3)
3 (4)
1 (9)

  • asorti(a,b)- 配列をインデックスでソートする

答え3

テーブル内の各セルをプレースホルダーとして扱い、目的の結果を作成すると、重複する行を並べ替えてカウントし、同じ数の列を持つ行がいくつあるかを特定できます。

a=$(sed 's/\([0-9]\+\)/1/g' file | sort | uniq -c)
dups=$( echo "$a" | cut -d' ' -f7 )

その後、各行の単語数を数えて、行に何列あるかを特定できます。

words=$(echo "$a" | cut -d' ' -f8- | awk '{print NF}')
paste <(echo "$dups") <(echo "$words")
4       1
1       3
3       4
1       9

答え4

最もシンプルなバージョンは

cat data.txt | awk '{counts[NF] += 1} END { for (row_count in counts) { printf "%d (%d)\n", counts[row_count], row_count; }'

NF行内のフィールド数を指定する変数を使用し、辞書内のそれに関連付けられた関連値を更新するだけです。次に、ストリームの最後で、辞書のすべてのキーを反復処理し、要求された形式で出力します。

関連情報