
以下の(数千または数百万)の値のリストがあります。
echo -e "y\ny\ny\nu\ni\no\no\nl\no\nj\nk\nl\nk\nl\nk\nl\nk\nl\nk\nl\no\nu\no\no\nu\ny\nl\ni\nq\nw\ne\nr\nt\na\ns" > list.txt
リスト内の各値が表示される回数を計算し、リスト内keep
の項目の一部を表す最も一般的な値()を選択したいと思います。実際のデータセットから切断されたことには興味がありません。
現在の作業コードは以下を使用sort | uniq | sort
しますawk
。
keep=0.50
sort list.txt | uniq -c | sort -nr > temp
awk -v keep=$keep 'NR==FNR {s+=$1}; NR!=FNR {c+=$1; print $0}; c > (s * keep) {exit 0}' temp temp
7 l
6 o
5 k
しかし、両方のコードは非常にぎこちないようです。もっと良い方法がありますか?正しいクエリが見つかりません(したがって、この質問のタイトルが間違っています)。
答え1
単一のawk
コマンド(GNUバージョン)を使用して、含まれる値に基づいて配列を一意に並べ替えることができます。count
ファイル内の各行の発生回数を一意に計算する連想配列です。
これは、値の降順で配列内の項目をソートするPROCINFO["sorted_in"] = "@val_type_desc"
GNU構成です。その後、繰り返して発生回数を合計し、終了条件が一致するまで高周波ペアを印刷します。awk
count
awk -v keep=0.50 '
{
count[$0]++
}
END {
PROCINFO["sorted_in"] = "@val_type_desc"
for (i in count) {
sum += count[i]
print i, count[i]
if (sum > (NR * keep)) {
break
}
}
}' list.txt