単語リストファイルで単語数を数えるときに発生順序を維持する方法

単語リストファイルで単語数を数えるときに発生順序を維持する方法

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つのファイル(配列として保存)の行を@b2番目のファイル(配列として保存)の行と一致させ、発生回数(Baggingなど)を計算する一般的なソリューションです。

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

https://docs.raku.org/type/Bag
https://raku.org

関連情報