.csvファイルで最も一般的な10の単語を見つける必要があります。ファイルは、各行にカンマ区切りの単語が含まれるように構成されています。同じ行に同じ単語が複数回繰り返されると、1と計算されます。したがって、次の例では次のようになります。
green,blue,blue,yellow,red,yellow
red,blue,green,green,green,brown
緑、青、赤は2と計算し、黄色と茶色は1と計算します。
同様の質問が以前に要求されたことがわかり、1つの解決策は次のとおりです。
<file.csv tr -c '[:alnum:]' '[\n*]' | sort|uniq -c|sort -nr|head -10
ただし、次のように、単語が同じ行に表示される回数を計算します。
4 green
3 blue
2 yellow
2 red
1 brown
これは実際に私に必要なものではありません。助けが必要ですか?また、コマンドの簡単な説明と同様の質問で見つけたコマンドが必要なタスクを実行しない理由に感謝します。
答え1
GNUgrep
または互換製品を使用してください。
$ grep -nEo '\w+' file.csv|sort -u|cut -d: -f2-|sort|uniq -c|sort -k1rn|head
2 blue
2 green
2 red
1 brown
1 yellow
答え2
パールを選ぶかもしれない
uniq
モジュールの内容を使用して、List::Util
各行の重複エントリを削除します。- ハッシュを使用して結果の発生回数を計算します。
例えば
perl -MList::Util=uniq -F, -lnE '
map { $h{$_}++ } uniq @F
}{
foreach $k (sort { $h{$b} <=> $h{$a} } keys %h) {say "$h{$k}: $k"}
' file.csv
2: red
2: green
2: blue
1: yellow
1: brown
sort
coreutilsを使用するしかない場合は、uniq
シェルループを追加して同様のアルゴリズムを実装できます。
while IFS=, read -a words; do
printf '%s\n' "${words[@]}" | sort -u
done < file.csv | sort | uniq -c | sort -rn
2 red
2 green
2 blue
1 yellow
1 brown
しかし、参考にしてくださいシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?
答え3
awk
連想配列と簡単な論理チェックを使用できます。
awk -F, '
{split("", c); for (i=1; i<=NF; i++)
if (!c[$i]){c[$i]++;wds[$i]++}}
END{for (wd in wds) print wds[wd], wd}' file
出力
1 brown
2 red
1 yellow
2 blue
2 green
牙
フィールド区切り記号を次のように設定します。,
awk -F, '
1行に複数の単語が表示されることを確認するために計算するか、またはc
を使用して各行の先頭の単語数が空であることを確認し、フィールドをdelete c;
繰り返しsplit("", c)
ます。
{split("", c); for (i=1; i<=NF; i++)
または
{delete c; for (i=1; i<=NF; i++)
$i
この行の単語がまだ表示されていない場合は、!c[$i]
その単語のカウンタをc[$i]++
1に増やします(単語が同じ行に再び表示されると、条件付きテストは失敗します)。その後、wds[$i]++
テストが失敗しない場合は、総数を増やします。言葉の
if (!c[$i]){c[$i]++;wds[$i]++}}
ファイルが完成したら、配列を繰り返してwds
数wds[wd]
と単語を印刷します。wd
END{for (wd in wds) print wds[wd], wd}' file
楽しく
awk
連想配列ビットなしのハッキング
awk -F, '{for (i=1; i<=NF; i++) print NR, $i}' file |
sort | uniq | awk '{print $2}'| sort | uniq -c | sort -nr
awk
行番号が前になるようにフィールドを削除し、行の重複をsort | uniq
失い、awk
番号をもう一度失い、元のコードに戻します。
答え4
awkには重要な必須タスクを実行するスクリプトがあります。
awk -F, '
{
i = split( "" , seen ) ;
while( ++i <= NF ) if( ++seen[$i] == 1 ) count[$i]++;
}END{
for( word in count ) print count[word] , word
}' file | sort -rn | head
仕組みは次のとおりです。
- 入力ファイルの各行に対して、次の操作を行います。
i
0に再初期化し、seen
新しい行ごとに配列を消去しますi=split("",seen)
。seen
各フィールドの配列の作成++seen[$i]
- この行では、aフィールドが最初に表示されたときにそのフィールドの数を計算します。 (
count[$i]++
)。 - すべての行が処理されると
END
、 for( word in count )
計算された各単語について- すべての単語とその数を印刷します
print count[word] , word
。 - 最後に、awkは出力を生成した後に数値でソートします。
sort -rn
- 最初の10行を選択します
head
。
私たちはこれをもう少し不思議な行で書くことができます:
awk -F, '{i=split("",a);while(++i<=NF)a[$i]++||c[$i]++}END{for(i in c)print c[i],i}' file|sort -rn|head