マッチした行をランダムに3行出力する方法

このQ&Aのポイント
  • リストファイルから特定の項目にマッチする行をランダムに3行選んで出力する方法について説明します。
  • リストファイルの内容を読み込み、マッチする行を選び出す方法を解説します。
  • マッチした行を項目ごとにランダムに選んで出力する方法を示します。
回答を見る
  • ベストアンサー

マッチした行をランダムに3行出力したい

毎度お世話になっております。 今夜も躓いてしまってどうにもならないので、お力をお貸しいただけませんでしょうか。 以下のようなリストファイルがあります。 ------------------ 項目1 項目2 ・・・ ------------------ このリストにマッチした行を、リストの項目ごとにランダムに3行選んで出力したいです。 マッチした行を取り出すところまでは、以下のような形でできたのですが、 ここから先をどのように書けばいいのかわかりません。 ------------------ my $list = 'リストファイル'; open (IN, "$list"); my %l; while(<IN>) { chomp; $l{$_}++; } close IN; while(<DATA>) { my ($xx,$yy) = split(/\t/,$_); if (exists($l{$xx})) { # print; # ここから先がわかりません } } __END__ 項目1 N1 項目1 N2 項目2 N3 項目2 N4 項目2 N5 項目1 N6 項目2 N7 項目2 N8 項目2 N9 項目1 N10 ------------------ 以下のような出力結果にしたいです。 ------------------ 項目1 N2 項目1 N6 項目1 N10 項目2 N3 項目2 N5 項目2 N9 ------------------ どうぞよろしくお願いいたします。

  • Perl
  • 回答数3
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • e_watt
  • ベストアンサー率71% (25/35)
回答No.3

「特定の項目を持つ配列」を作るには、別に split して連想配列にしなくても、 配列の要素から目的の条件に合う要素を抽出する grep を使えば1行で書けます。 あらすじはこんな感じ my @items = <IN>; # (この行の上下のopen/closeは記述省略) my @data = <DATA>; # 両方一気に読み込んじゃうことの是非は置いとく map { chomp; # 改行がついたままなので削る my $pat = $_; # grep の中で $_ が使われるので別の変数にコピる my @line = grep(/^$pat/, @data); # ここでマッチする行を抽出 # ここで回答 No.1 への補足にある、ランダム出力のループを使う } @items; # "map", "foreach (@items)", "while (<IN>)" のどれが好みかは置いとく

hachibunbunbun
質問者

お礼

お礼が遅くなってすみません。 勉強になりました!ありがとうございます。

その他の回答 (2)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

「ある配列からランダムに 3個の要素を表示する」ことはできるんだよね. だとしたら, 「特定の項目を持つ配列」を作ればいい. つまり, 今のプログラムとは逆に先にデータを読み込んで, 「リストファイル」からはあとで入力する.

hachibunbunbun
質問者

お礼

お礼が遅くなってすみません。 勉強になりました!ありがとうございます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「マッチする」かどうかはとりあえず脇に置いて, 「ファイルの内容をランダムに 3行表示する」ことはできますか?

hachibunbunbun
質問者

補足

以下のように書いて、「ファイルの内容をランダムに 3行表示する」ことは一応できたのですが、 「項目ごとにランダムに 3行」がどうやったらいいのかわかりません・・・。 -------------------- @line = <DATA>; for ($i = 0; $i < 3; $i++) { $r = int(rand(@line)); $s = splice(@line,$r,1); print $s; } __END__ 項目1 N1 項目1 N2 項目2 N3 項目2 N4 項目2 N5 項目1 N6 項目2 N7 項目2 N8 項目2 N9 項目1 N10 --------------------

関連するQ&A

  • マッチした行の上の行を抽出

    初心者で至らぬ点が多々有りますが、宜しくお願いします。 環境はWindows7-64bit、ActivePerl 5.12.4 Build(64bit)を使用しています。 テキストが数百個有り、全て以下のような構成になっています。 文章1 文章2 文章3 kwd 文章4 kwd 文章5 文章6 kwd    ~以下略~ ファイル郡をリストとして読み込み、それぞれのファイルに対して kwdをキーとして検索し、該当した行の上の行を抽出しようとしています。 ~ファイルリスト読み込みルーチンは省略、以下各ファイル毎のサブルーチン~ sub execute { open(INP, "$inp"); #ファイル読み込み open(OUT, ">rep\\$inp"); #ファイル書き出し(フォルダを変えて同名) while(<IN>){ if($_ =~ m/kwd/){ #現在の行が"kwd"を含んでいたら print OUT $prev; #前の行を抽出のつもり } $prev = $_; #現在の行データを$prevに格納 } close(INP); close(OUT); } $_には現在の行データが入っていると認識しており 上記の書き方で$prevには一段上の行データが入るのでは と思ったのですが、現状$prevを出力してもカラです。 文法ミスよりも、そもそも考え方が間違っているような気がして なりませんが、どうか解決法を教えて頂きたく。

  • definedの使い方が間違ってますか?

    こんばんは。 色々試してみたのですが、どうしてもうまくいかないので質問させてください。 リストの$f1とファイルの$aaがマッチして、 かつリストの$f3とファイルの$bbがマッチした場合に、 $f4を付け加えてprintしたいのですが、 ★マークの処理で、リストの$f3とファイルの$bbがマッチしていないものまで printされてしまうことがあります。 $aaとマッチするものがリストに2つ以上ある時にこの現象がおきるようなのですが、 どの辺を直したらよいのかわかりません。 definedの使い方がおかしいのでしょうか? 見よう見まねで書いたので、▲マークあたりの指定も自信がありません。 #リスト読み込み open LIST, "./list" or die; while (<LIST>) { chomp; if (/(.*) (.*) (.*) (.*)/) { $f1 = $1; $f2 = $2; $f3 = $3; $f4 = $4; } $xx{$f1} = $f4; #▲ $yy{$f1} = $f3; #▲ } close LIST; #ファイル読み込み if ($#ARGV >= 0) { @files = @ARGV; } foreach $file (@files) { open FILE, $file; while (<FILE>) { chomp; if (/^([^t]+)\t(.*)$/) { $aa = $1; $bb = $2; if (defined($xx{$aa})) { if (defined($yy{$bb})) { # ★ print "$aa\t$bb\t\#【$xx{$aa}】\n"; } } } } close FILE; } どうかご教示お願いいたします。

    • ベストアンサー
    • Perl
  • Perlで行頭にある文字が含まれている行を全部削除して詰めたい

    perl初心者です。以下のようにデータがならんでいる時、 test111 aaaaaaaaabbbbbbbbcccccc test112 aaaaccccabbbbbbbbcccccc test113 aaaaccaaabbbbbbbbcccccc test114 acccaaaaabbbbbbbbcccccc test111 aacaaaaaabbbbbbbbcccccc test112 accaaaaaabbbbbbbbcccccc test113 aaacccaaabbbbbbbbcccccc test114 aaaaaccaabbbbbbbbcccccc test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。 途中からわかりません。 行を削除する関数が調べても見つからないのです。 #!/usr/bin/perl ; open(IN, "test.doc") or die ; open(OUT, ">testout.doc"); while(<IN>) { chomp ; if (/(\S+)/) { $name = $1 ; if ($name =~ /^test112(\S+)/) { #ここでマッチさせて、一気に行を削除して、しかも行を詰めたいのですが ; } print OUT " \n" ; } } close (IN) ; close (OUT) ; 大変困っております。宜しくお願いします。

    • ベストアンサー
    • Perl
  • すべてにパターンマッチしてしまうのはなぜ?

    以下のようなスクリプトを書いた時に my @list = ('ab', 'cd', 'efg', 'hijk'); foreach my $line (@list){ #print "$line\n"; if ($line =~ m/ ^a| ^e| /x){ print "$line "; }} 標準出力は ab cd efg hijk となり、@list内の要素すべてにマッチしたことになってしまいます。 理由がわからずごちゃごちゃといじっていると、検索部分を =~ m// としても全く同じことになります。 これは、どの配列の要素も空(くう?)を含むためにヒットしてしまう・・・ ということなのでしょうか? どのように理解すれば良いのでしょうか?基本的な質問で申し訳ございませんが、どなたかよろしくお願い致します。

    • ベストアンサー
    • Perl
  • 重複した行と、重複していない行をわけて出力したい。

    お世話になります。Oracle9iで、 タイトル通りですが、一つの表から 重複したレコード・重複していないレコード を出力したいのですが、「こうかな?」と思った SELECT文が30分ちかく返ってきません(^^; 他に方法があれば教えて頂きたく質問致しました。 よろしくご教授下さい! (以下のSQLで、重複した行は"exists"で、 重複していない行は"not exists"もしくは "having count(*) = 1"でできるかな? と思ってましたが・・・) テーブル名:結果 キー項目(とみなすカラム):番号・名称・年月日 出力したい項目:結果.データ・もしくは結果.* --データが複数 select a.番号,a.名称,a.年月日,a.データ from 結果 a where exists --キーの重複SELECT ( select 番号,名称,年月日,count(*) from 結果 j where j.年月日 >= '1992/04/01' and j.年月日 <= '1993/03/31' and a.番号= j.番号 and a.名称= j.名称 and a.年月日 = j.年月日 group by j.番号,j.名称,j.年月日 having count(*) > 1 )

  • 2行読み込んで一行戻り、また2行読み込む

    2行読み込んで一行戻り、また2行読み込む はじめまして、現在、「2行読み込み、一行戻り、また2行読み込む」処理のものを作成しています。 具体的には、 A B C D E と5行に渡り記述されたファイルを上記の旨で表示させる場合、 A B B C C D D E としたいのですが、 filename = ARGV[0] ABCDE = [] file = open(filename) while f = file.gets do  f.chomp!   g = file.gets   g.chomp!  p f  p g end file.close とすると出力は "A" "B" "C" "D" abcde.rb:9: private method `chomp!' called for nil:NilClass (NoMethodError) もちろん2行読み込んで、そのまま次の2行を読み込む記述のため上記のようになってしまいます。 まとめますと、 「一行戻るための記述がわからないので、それを実現するための記述を教えてほしい」 ということです。 rewindを使うと先頭まで戻ってしまうのでどうしたらいいのかさっぱりです。 わかりづらくて非常に申し訳ない、初歩的であろう質問ですがよろしくお願いします。 rubyは1.8.6を使っています。

    • ベストアンサー
    • Ruby
  • ファイル操作について

    別スレ立てているので、ルール違反になっちゃいますかね? もしそうであればゴメンナサイ… sub fanc{ my @array = @_; my $ag = shift @array; my $n1 = 'AAA.csv'; my $n2 = 'BBB.csv'; my $n3 = 'CCC.csv'; my $n4 = 'DDD.csv'; my $n5 = 'EEE.csv'; ・ opendir(DIR, "C:/Program Files/Apache Group/Apache2/cgi-bin/test");my @pairs = readdir(DIR); close(DIR); if($ag == 1){@files = grep(/$n1/,@pairs); } if($ag == 2){@files = grep(/$n2/,@pairs); } if($ag == 3){@files = grep(/$n3/,@pairs); } if($ag == 4){@files = grep(/$n4/,@pairs); } if($ag == 5){@files = grep(/$n5/,@pairs); } if($ag == 6){@files = grep(/$n6/,@pairs); } ・ $dfile1 = $files[0]; open(IN,"$dfile1") or exit; chomp(my $row01 = <IN>); chomp(my $row02 = <IN>); chomp(my $row03 = <IN>); chomp(my $row04 = <IN>); chomp(my $row05 = <IN>); chomp(my $row06 = <IN>); ・ close(IN); my @col01 = split(/,/, $row01); my @col02 = split(/,/, $row02); my @col03 = split(/,/, $row03); ・ ・ こういったコードをもっと短く、書くやり方を知りたいです。 grepでヒットするのが複数の場合もあるため、当初はForeach文とフOpenで配列@filesに入った ファイルを全て展開して、配列、又は変数に格納しようと思ったのですが、どうやって複数の配列をOpen関数で扱えばいいのか解りません。 もしそうでなければ、現在は一つのファイルに対しての処理ですが、残ったファイルに関しても関数を回す方法があれば、ご教授願えませんか??あ、あと、CODE(xxxxxx)ってなんのことでしょう?

    • ベストアンサー
    • Perl
  • Perl マッチング 1行だけ表示

    おそれいります。 abc.txtに保存されたデータを、xyz.cgiから特定ワードに合った最初の行だけを抽出したいのですが、 うまくいきません。 open(OUT, "< ./abc.txt"); while($data = <OUT>){ chomp($data); @ip = split(/,/,$data); if($ip[0] =~ /word/){ 処理 } とすると、マッチする行が全て表示され、 Whileを外すとデータの1行目だけを判定するみたいで、 wordという文字列が含まれるレコードが見つかったらそのマッチした最初のデータだけを表示したいのです。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • データからある文字列の次の行を出力するには

    perlの初心者です。はじめまして。 質問タイトルそのままなのですが、データからある文字列の次の行を出力するにはどのような記述をすればよろしいでしょうか?よろしくお願いします。 ・データは1ファイルで2000あります。1つのデータは[X,Y]で始まり、次の[X,Y]の前までになります。 ・出力はCSVファイル。 ・DAT errがあった場合はその次の行を出力。なかったら、DAT列は空白にする。 #!/bin/perl open(FILE,"<$ARGV[0]"); open(OUT,">$ARGV[0].csv"); ########################## err count ########################### print OUT "X,Y,NUMBER,DAT,\n"; while(<LOG>){ if($_ =~ /X=(.+)\,Y=(.+)/){ chomp($_); print OUT "\n$1,$2,"; } if($_ =~ /NUMBER (.+)/){ print OUT "$1,"; } if($_ =~ /DAT err/){ print OUT "PASS,0,"; } } close(OUT);

    • ベストアンサー
    • Perl
  • 配列から効率よくマッチさせるには

    配列からなるべく高速にマッチさせたいと思っているのですが、 たとえば、以下のようにリストをlist.datへ保存させている場合で キーワード1<>filename1<>time1<> キーワード2<>filename2<>time2<> フォームから入力されたキーワードとマッチさせてfilenameの要素を 取り出すといった場合、通常の配列ループを利用すると open(IN,"list.dat"); while (<IN>) { ($key,$name,$time) = split(/<>/); if($FORM{'key'} eq $key) { last; } } のようにしてフォームで入力したものとマッチさせるような 形になると思いますが、連想配列と言うものを活用すると もっと効率よく高速に処理できるのでしょうか? もしよろしければ出来る限り効率の良い方法(ソース)を 教えていただけましたら幸いです。

    • ベストアンサー
    • Perl

専門家に質問してみよう