電子書籍の厳選無料作品が豊富!

現在perlを勉強中の身です。

1行に1英単語があり、それが100~200行に渡ってあるファイルがあります。
このファイルの単語に重複しているものはありません。Xとします。

また別のファイルにも同様に1行に1英単語があり、それが100~200行に渡ってあるファイルがあります。
このファイルの単語は重複しているものがあります。Yとします。

当然、最初のファイルにある単語もない単語もあります。

ファイルXから単語を読み取りYでその単語が何回出現したかチェックして単語と出現回数を出力するようなプログラムを組みたいと考えています。

参考書やインターネットで調べたところ、単語を数えるプログラム等はあるのですが、ファイルを読み込みさらにファイルを読み込んで比較する、といった流れのプログラムを見つけることができませんでした。

遠回りな考え方だと
例えば
ファイルX
a b c d(本当は単語間は改行があり1行1単語なのですが、見やすさのためにこのように表記しました。)
ファイルY
c c d e f
とあった場合まず二つのファイルを結合し
ファイルZ
a b c d c c d e f
として二回以上出現した単語のみを抜き出し
ファイルZ'
c 2
d 1 (この時出現回数を-1回する)
としてファイルXと結合して出現回数を足して-1すると
ファイルX'
a 0
b 0
c 2
d 1
のようにできるのではないかと考えてはいます。しかし遠回り過ぎてスマートではないように感じます。

どのような考え方、そしてどのようなプログラムを組めばよいのでしょうか。ご教授お願い致します。

A 回答 (5件)

1対nマッチングを応用してもできるのではないかと思います。



まず、前提として、

 1.1行に重複していない1英単語だけのファイルを「xxx.txt」とします。
 2.1行に重複している可能性のある1英単語だけのファイルを「yyy.txt」とします。
 3.上記2つのファイルの英単語は昇順に並んでいるものとします。
 4.「xxx.txt」と「yyy.txt」の両方にある英単語については「英単語と出現件数」を出力します。
 5.「xxx.txt」だけにある英単語については「英単語と出現件数(結果として0)」を出力します。
 6.「yyy.txt」だけにある英単語については何も出力しません。
 7.4と5での出力ファイルを「zzz.txt」とします。

とします。

上記の前提で作成したのが以下のサンプルです。

---------------------------------------------------------------------------------

# ファイルのオープン
open(IN1,"xxx.txt");   #マスターファイル
open(IN2,"yyy.txt");   #トランザクションファイル
open(OUT1,">zzz.txt");   #出力ファイル

# 初期値設定
$high_value = pack("h8","ffffffff"); #終了判定
$in1_key = undef;  #マスタキー
$in2_key = undef;  #トランザクションキー
$occur_ctr = 0;   #出現回数

# 1件目のデータ入力
s_in1();
s_in2();

# 主処理
until ($in1_key eq $high_value && $in2_key eq $high_value) {

# マッチングの時(両方のファイルにデータがある)
 if  ($in1_key eq $in2_key) {
  until ($in1_key ne $in2_key) {
   $occur_ctr++;
   s_in2();
  }
   $out1 = join("\t",$in1_key,$occur_ctr);
   print OUT1 "$out1\n";
   s_in1();
   $occur_ctr = 0;
 }

# マスタオンリーの時(マスタファイルだけにデータがある)
 elsif ($in1_key lt $in2_key) {
   $out1 = join("\t",$in1_key,$occur_ctr);
   print OUT1 "$out1\n";
   s_in1();
 }

# トランザクションオンリーの時(トランザクションファイルだけにデータがある)
 elsif ($in1_key gt $in2_key) {
   s_in2();
 }
}

# マスタファイル入力
sub s_in1 {
 if  ($line1  = <IN1>) {
   chomp($line1);
   $in1_key = $line1;
 }
 else {    #マスターファイルが終了のとき
   $in1_key = $high_value;
 }
}

# トランザクションファイル入力
sub s_in2 {
 if  ($line2  = <IN2>) {
   chomp($line2);
   $in2_key = $line2;
 }
 else {    #トランザクションファイルが終了のとき
   $in2_key = $high_value;
 }
}
# ファイルのクローズ
close(IN1);
close(IN2);
close(OUT1);

---------------------------------------------------------------------------------

※なお、カラムをそろえるために、全角スペースを使っていますので、
 このままコピー・ペーストしても動作しません。この点はご注意ください。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。連想配列について勉強し、どうしてもできなかった時に参考にさせて頂きます。わざわざプログラムまで書いて頂いてありがとうございました。

お礼日時:2011/12/26 23:41

「連想配列にキーが存在するかどうか」を判定するなら, 一般には defined より exists の方が適切です>#4. defined を使うと「値が存在しない」場合だけでなく, 「値が undef である」場合にも偽になります. これに対し exists なら前者の場合のみ偽になります.



もちろん今の場合には「値が undef であるようなキー」を作らないからどっちでも同じことだし, もっとはっきり言えば「そもそも definedness の判定すら不要」だったりしますが.
    • good
    • 0
この回答へのお礼

何度も回答ありがとうございます。色々試してみようかと思います。ありがとうございました。

お礼日時:2011/12/27 14:19

この例で連想配列(ハッシュ)使うときに注意するのは「Yにだけ存在する単語」の時ですね。


$h{key}で、連想配列にkeyが無い時は未定義値になるので、definedで判定できます。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。試行錯誤しながら頑張ってみます。

お礼日時:2011/12/27 14:18

Xの各行を読み込んでいき、連想配列(ハッシュ)のキーにする。

値は0。
Yの各行を読み込んでいき、その行の単語をキーにして連想配列の項目を指定し、値を1加算。
最後に連想配列全体を出力。
これが一番わかりやすい方法です。

やろうとしていることのレベルを考えると、プログラムを全部教えてしまったら意味がないので書きません。
連想配列について調べてください。
https://www.google.com/search?q=Perl+%E9%80%A3%E …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。連想配列について勉強してみます。ありがとうございました。

お礼日時:2011/12/26 23:40

十分なメモリがあるなら


ファイルY から単語を読み込んで出現回数をハッシュで記憶し, ファイルX の単語と突き合せる
のが単純かな.
    • good
    • 0
この回答へのお礼

回答ありがとうございます。連想配列について勉強してみます。ありがとうございました。

お礼日時:2011/12/26 23:38

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!