ページ 1 / 1
perlで複数の文字列をランダムに抽出
Posted: 2011年5月23日(月) 01:49
by yam
以前お世話になったyamと申します。どうぞよろしくお願いします。
あるファイルから、複数の文字列をランダムに抽出したいと思い、いろいろ調べていたところ、
以下のホームページに行き当たりました。
http://chaichan.web.infoseek.co.jp/qa6500/qa6619.htm
このページを参考にすれば、自分がやりたいことができるのではないかと思いました。
私がやりたいことはあるファイルの中に、以下のような「。」で改行された文字列が1000あります。
その中から重複せずに100の文字列を抽出したいです。
------------------------------
おはようございます。
こんにちは。
こんばんは。
さようなら。
今日は、いい天気ですね。
じゃ、また会いましょう。
………
------------------------------
そこで、先のページを参考にしてプログラムを書いてみたのですが、どうしてもいくつかの文字列が重複してしまいます。
よろしければ重複せずに抽出する方法を、お教え頂けないでしょうか。
何卒よろしくお願い致します。
コード:
open IN,"in.txt" or die "file in.txt did not opened/n";
@all = <IN>;
close IN;
open OUT, ">out.txt";
$num = 100;
@line = ();
while($#line<$num-1){
$a = int(rand($#all+1));
for(@line){
next if($a == $_)
}
push(@line,$a);
}
print OUT $_,":",$all[$_] for(@line);
close OUT;
Re: perlで複数の文字列をランダムに抽出
Posted: 2011年5月23日(月) 04:17
by トントン
おはようございます。
トントンです。
コード:
use strict;
open my $in, "<C:/in.txt" or die "not found\n";
my @all = <$in>;
my @lines;
my @tmp;
my %rep;
die "input text is insufficient\n" if(@all < 10);
foreach (0..9) {
my $index = int(rand(@all - 1));
push(@tmp, $all[$index]);
}
@lines = grep {++$rep{$_} < 2} (@tmp, @tmp);
仕様が一部わからないので下記部分だけ。
>よろしければ重複せずに抽出する方法
参考になれば良いのですが。
# ちなみにnext if($a == $_) って 行番号比較ですか?
Re: perlで複数の文字列をランダムに抽出
Posted: 2011年5月23日(月) 13:14
by yam
トントンさん
こんにちは、yamです。
まずはわざわざお返事頂き、ありがとうございます。
> 仕様が一部わからないので
言語仕様については私もわかりませんでした。
私はPerlも含めプログラムを勉強し始めたばかりなので、理解が浅いことも確かですが、
「$#」などの書き方について疑問を持ちました。そして調べてはみたのですが、
結局のところ、わかりませんでした。
> 下記部分だけ。
>> よろしければ重複せずに抽出する方法
まずはランダムに10の文字列を抽出する方法をお示しくださったのですね。
勉強させて頂きます。ありがとうございました。
(なお、実際に動かせて頂きましたが、確かに重複することなく文字列を抽出することができました。ありがとうございます!)
ただ、上に示させて頂いたホームページで「これはいいなぁ」と思ったのは、行数が指定できる点と、取得した行数を最後に取得している点でした。
このような形で書くことはできないでしょうか。再度ながら、皆様、何卒よろしくお願い致します。
PS
> # ちなみにnext if($a == $_) って 行番号比較ですか?
そうだと思います。そうだと思いますなんて、無責任な表現ですが (^_^; 先ほどのページにもそのように記されておりました。
for(@line){next if($a==$_);} #重複していたら、次のループへ
取得した行が重複しているのが問題でしたので、私もここらあたりをいろいろ変更してはみたのですが、結局のところどうしていいかわからず、皆様に質問させていただきました。
Re: perlで複数の文字列をランダムに抽出
Posted: 2011年5月23日(月) 17:46
by ISLe
yam さんが書きました:for(@line){next if($a==$_);} #重複していたら、次のループへ
ここのnextはwhileの次のループを期待してのことでしょうけど、実際はこのforの次のループに移行するのでまったく意味のないコードになってしまっています。
コード:
while(@line < $num){ # -1不要
$a = int(rand(@all)); # +1不要
$c = 0;
for(@line){
++$c if($a == $_); # 重複してたらカウント
}
push(@line, $a) if($c < 1); # カウントされなかったらOK
}
for(@line){ print OUT ($_+1).":".$all[$_]; } # テキストの行数は1からはじまるようにした
こちらはあらかじめ行番号を付けておいて、1行ずつ抜き出す方法で書いてみました。
コード:
$c = 0;
@all = map(++$c.":".$_, @all);
while(@line < $num){
$a = int(rand(@all));
push(@line, $all[$a]);
splice(@all, $a, 1);
}
for(@line){ print OUT $_; }
(修正)
print OUT~の箇所の構文エラー(ブロックの付け忘れ)を修正しました。
Re: perlで複数の文字列をランダムに抽出
Posted: 2011年5月23日(月) 19:58
by yam
ISLeさん
yamです。以前もお教え頂きましたが、この度もいろいろお教え頂き、
本当に感謝しております。ありがとうございます。
また詳しい解説も頂いたため、どうしてうまくいかなかったのか、その原因もよくわかりました。
とても勉強になりました。ありがとうございました。
ISLe さんが書きました:
ここのnextはwhileの次のループを期待してのことでしょうけど、
実際はこのforの次のループに移行するのでまったく意味のないコードになってしまっています。
なるほど、そうだったのですね。このご指摘、目から鱗が落ちる思いでした!
また、
コード:
$c = 0;
for(@line){
++$c if($a == $_); # 重複してたらカウント
}
push(@line, $a) if($c < 1); # カウントされなかったらOK
この箇所についても本当に勉強になりました。ありがとうございました。
それに、もう一つお書きくださったスクリプトについても、参考にさせて頂きました。
コード:
$c = 0;
@all = map(++$c.":".$_, @all);
最初にカウンタをリセットしておいて、そして1行ずつ番号を付けるという方法ですね(その後読み込み)。
おっしゃる通り、こんな方法もあることはわかるのですが、ご指摘されるまで全く気が付きませんでした。
(本当に勉強になりました!)
ISLeさんには前回もお助けくださいましたが、今回もお助けくださったこと、本当に感謝しております。
そして本当に良い勉強ができました。ありがとうございました。
yam
PS
どちらのスクリプトも print のところにエラーが出るのですが、
for(@line) をいちばん後ろに持って行くことで回避されました。