2つのファイルがあります。
file1
固有の単語リストfile2
複数の文を含む
file1
各単語の発生回数を一覧表示するタブ区切りのファイルを出力したいと思います。file2
ファイル1にリストされている順序を維持しながら。
たとえば、
file 1
:dog apple cat
file 2
:the dog played with the cat and the cat was white. the boy ate the apple.
- 希望の出力:
dog 1 apple 1 cat 2
従来試してみた回答コミュニティはすべて出力をソートします。
答え1
すべてのUnixシステムのすべてのシェルでPOSIX awkを使用してください。
$ cat tst.awk
BEGIN { OFS="\t" }
NR==FNR {
words[NR] = $1
next
}
{
$0 = " " $0 " "
gsub(/[^[:alpha:]]+/," ")
for ( i in words ) {
word = words[i]
cnts[word] += gsub(" "word" ","&")
}
}
END {
for ( i=1; i in words; i++ ) {
word = words[i]
print word, cnts[word]+0
}
}
$ awk -f tst.awk file1 file2
dog 1
apple 1
cat 2
上記では、「単語」がすべてアルファベット文字で、一致が大文字と小文字を区別したい場合、または例のように入力がすべて小文字で、例のようにfile1の単語が一意であると仮定します。
答え2
使用幸せ(以前のPerl_6)
@a
以下は、1つのファイル(配列として保存)の行を@b
2番目のファイル(配列として保存)の行と一致させ、発生回数(Bag
gingなど)を計算する一般的なソリューションです。
raku -e 'my @a = dir(test => "alphabet.txt").IO.lines.reverse; my @b = $*ARGFILES.lines; \
for @a -> $a {@b.grep(/<$a>/).Bag.pairs.say};' alphabet.txt alphabet.txt
設定すると、Rakuには場所とファイル名が@a
提供されます。設定時にコマンドラインに1つ以上のファイルを入力し、Rakuの動的変数を介して読み込みます。dir()
test => "…"
@b
$*ARGFILES
汎用入力はいalphabet.txt
、1行に1文字ずつ、Rakuで読んだ直後に反転して、「z」..」a」の順に配列を配置します。
汎用出力alphabet.txt
(コマンドラインに「a」..「z」のコピーを2つ入力する場合):
(z => 2)
(y => 2)
(x => 2)
(w => 2)
(v => 2)
(u => 2)
(t => 2)
(s => 2)
(r => 2)
(q => 2)
(p => 2)
(o => 2)
(n => 2)
(m => 2)
(l => 2)
(k => 2)
(j => 2)
(i => 2)
(h => 2)
(g => 2)
(f => 2)
(e => 2)
(d => 2)
(c => 2)
(b => 2)
(a => 2)
returnがarrayと同じ順序を維持する方法と、Rakuが上記の出力を生成するために@a
呼び出しを必要としない方法に注意してください。sort
my @b = $*ARGFILES.lines.words
最後に、OPの問題を解決するために上記のコードで変更する必要がありますmy @b = $*ARGFILES.lines
。
[タブ区切りの出力を取得するには、上記のコードで.put
代わりに使用してください。.say
これにより、周囲の角かっこと=>
2つの列の間の矢印が削除されます。
最終コード:
~$ raku -e 'my @a = dir(test => "dog_apple_cat.txt").IO.lines.grep(*.chars); \
my @b = $*ARGFILES.lines.words; for @a -> $a { \
@b.grep(/<$a>/).Bag.pairs.put};' text.txt
dog 1
apple. 1
cat 2