プロが教えるわが家の防犯対策術!

初めまして、説明がうまく伝わらないかもしれませんがよろしくお願いいたします。

同じ値がN回続いた場合、その値をすべて出力するPerlのプログラムを作成中なのですが
とても長くなってしまい、スッキリとしたプログラムにしたいのです。
どうかお知恵を貸していただけないでしょうか。

現在、&&を使用してこのようになっています。
例:Aの値が5回連続して同じ値だった場合
for($i=1; $i<=1000; $i++){
 if(@A[$i]==@A[$i+1] && @A[$i+1]==@A[$i+2] && @A[$i+2]==@A[$i+3] && @A[$i+3]==@A[$i+4]){
  for($j=0; $j<=9; $j++){
   printf "@A[$i+$j], @B[$i+$j], @C[$i+$j]";
  }
 }
}

データはすべて数値で、スペース区切りのテキストデータです。
# ヘッダー
0.00 2.0 11.5
0.01 6.3 17.2
0.01 2.1 14.2
0.01 1.2 14.3
0.01 2.1 14.3
0.01 3.7 14.3
0.01 3.7 14.3
0.01 4.1 14.3
0.06 4.1 14.3
0.01 4.1 14.9
0.01 4.1 14.9
0.03 4.1 14.8
・・・

連続した値が50回、100回だった場合になるとif文の条件式が長くなってしまい
その都度変更がとても大変になってしまい困っています。
どうか、よろしくお願いいたします。

A 回答 (7件)

Perlはちょっとうろ覚えですが、単に取り出すだけなら文字列のまま取得してもいいかも。


------------------
$N= 5;

$n=$N-1;
@arr;
while ( $str =~ m/(([\d\.]+) [\d\.]+ [\d\.]+\n(?:\2 [\d\.]+ [\d\.]+\n){$n,})/og ){
push(@arr,$&);
}


#確認
print "<pre>";
foreach $var (@arr) {
print "$var<hr>";
}
print "</pre>";
------------------
~以上ではなく、厳密にN回なら カンマなしで{$n}
    • good
    • 0

再帰呼び出しで比較、カウンタ変数で連続回数を判定すればいいような気がします。



#!/usr/bin/perl
use strict;
use warnings;
use feature qw/say switch/;
use utf8;
use open IO => qw/:utf8 :std/;

my @list = <DATA>; # 比較する数値が入ったリスト
my @kaburi = (); # 繰り返しの数値が入るリスト
my $count = 0; # カウンタ変数

sub yobidasi {
my $num = shift @_;
$count++;
yobidasi(shift @list) if defined $list[0] && $num eq $list[0];
push @kaburi, $num if $count > 1; # ここの数値で連続回数を指定
$count = 0;
}

while (my $num = shift @list) {
yobidasi($num);
}
say @kaburi;


__DATA__
0.00 2.0 11.5
0.01 6.3 17.2
0.01 2.1 14.2
0.01 1.2 14.3
0.01 2.1 14.3
0.01 3.7 14.3
0.01 3.7 14.3
0.01 4.1 14.3
0.06 4.1 14.3
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.01 4.1 14.9
0.03 4.1 14.8


で、出力はこんな感じなると思います。

0.01 3.7 14.3
0.01 4.1 14.9

比較の条件がよくわからなかったので、行単位での文字列比較で再帰呼び出しを行っています。ここはsplit使うなりして、お好きなように設定してみてください。
    • good
    • 0
この回答へのお礼

お礼が遅くなり申し訳ありませんでした。
内容を理解するまで少し時間をいただけないでしょうか。

丁寧にご回答をしていただき、ありがとうございました。
何とか頑張ってみます。

お礼日時:2012/05/07 10:12

ぐだぐたで悪い。

Ano3ではなくAno4の書き落としです。
    • good
    • 0
この回答へのお礼

お礼が遅くなってしまい、申し訳ありませんでした。
プログラム内容について、私には少し難易度が高くて頭の中でグルグル回っています。
消化するまで少しお時間をください!

丁寧にお答えいただき、本当にありがとうございました。

お礼日時:2012/05/07 10:10

Ano3 書き落としすみません。

$strは文字列のままのデータ全部です。
$str = "
# ヘッダー
0.00 2.0 11.5
0.01 6.3 17.2
0.01 2.1 14.2
0.01 1.2 14.3
0.01 2.1 14.3
0.01 3.7 14.3
0.01 3.7 14.3
0.01 4.1 14.3
0.06 4.1 14.3
0.01 4.1 14.9
0.01 4.1 14.9
0.03 4.1 14.8
";
    • good
    • 0

こんな感じでしょうか。


指定回数を $limen に入れることで柔軟に繰り返し回数の条件を変更できます。
「同じ値が〇回続く」を if 文で判定するのではなく、内側のループ INNER_LOOP で現時点から1つづつカウンタを進めて1回1回判定していくようにしています。
値が同じであれば繰り返されているので、繰り返している回数を $reptation に増加していきます。
カウンタが指定回数まで達すると、条件を満たしたことを $is_recured に代入します。
外側のループ OUTER_LOOP の最後で $is_recured が真なら出力します。
出力の際はあらかじめ記録しておいた $repatation を使い、繰り返している回数分だけ出力します。

以下、例示します。
字下げに全角空白を用いてますのでコピペして試す場合は適宜削除して実行してください。

use strict;
my $data = <<'EOD';
#ヘッダー
0.00 2.0 11.5
0.01 6.3 17.2
0.01 2.1 14.2
0.01 1.2 14.3
0.01 2.1 14.3
0.01 3.7 14.3
0.01 3.7 14.3
0.01 4.1 14.3
0.06 4.1 14.3
0.01 4.1 14.9
0.01 4.1 14.9
0.03 4.1 14.8
EOD

# テキストデータを分割して各配列に入れる
my( @A, @B, @C );
foreach my $item ( split /\n/, $data ){
  next if $item =~ /^#/ ;
  my ($value_a, $value_b, $value_c ) = split / /, $item;
  push @A, 0+$value_a;
  push @B, 0+$value_b;
  push @C, 0+$value_c;
}

my $limen = 5; # 条件となる繰り返し回数
my $array_length = @A; # @A の要素数

OUTER_LOOP:
for( my $idx = 0; $idx < $array_length; $idx++ ){

  my $is_recured; # 繰り返し回数を満たしたかどうかを記憶する変数
  my $reptation = 1; # 繰り返された回数。1回は必ず繰り返すので初期値は1

  # 配列の最後まで次々と比較するループ
  INNER_LOOP:
  for( my $fore = 1; $idx + $fore < $array_length; $fore++ ){

    # 値が同じなら繰り返し回数を増加
    if( $A[ $idx ] == $A[ $idx + $fore ] ){
      $reptation += 1;
    }
    # 値が異なればこのループを抜ける
    else {
      last;
    }

    # 条件回数に達したらフラグをセット
    if( $reptation == $limen ){
      $is_recured = 1;
    }
  }

  # フラグが立っていれば、指定回数同じ値が続いているので出力
  if( $is_recured ){
    print "repeat same value $reptation times.\n";
    for( my $i = 0; $i < $reptation; $i++ ){
      print "$A[$idx+$i], $B[$idx+$i], $C[$idx+$i]\n";
    }
    print "----------------------\n";
  }
}

__END__
実行結果
repeat same value 7 times.
0.01, 6.3, 17.2
0.01, 2.1, 14.2
0.01, 1.2, 14.3
0.01, 2.1, 14.3
0.01, 3.7, 14.3
0.01, 3.7, 14.3
0.01, 4.1, 14.3
----------------------
repeat same value 6 times.
0.01, 2.1, 14.2
0.01, 1.2, 14.3
0.01, 2.1, 14.3
0.01, 3.7, 14.3
0.01, 3.7, 14.3
0.01, 4.1, 14.3
----------------------
repeat same value 5 times.
0.01, 1.2, 14.3
0.01, 2.1, 14.3
0.01, 3.7, 14.3
0.01, 3.7, 14.3
0.01, 4.1, 14.3
----------------------
    • good
    • 0
この回答へのお礼

丁寧に回答していただき有り難うございました。
こ、こんなに長くなってしまうんですね。
頑張って参考にさせていただきます。
有り難うございました!

お礼日時:2012/04/25 16:05

「ある値がどれだけ連続しているか」を数えればいいんだけど....



なんで @A[$i] なんだろう. $A[$i] にしない理由が思いつかない.

この回答への補足

すみません、実際のプログラムとデータはもっと複雑なので@A[$i]にしていました。
質問内容を省き過ぎて申し訳ありませんでした。

if文の条件式を簡略化したいのです。
現段階では「指定した回数分」を "&&"を繰り返し使用していて
非効率的なので困っています。

ご回答ありがとうございました。

補足日時:2012/04/25 09:49
    • good
    • 0

ifで判定するのではなく配列に格納し全てのデータを読み取ったら、配列を確認するという処理をしては?

    • good
    • 0
この回答へのお礼

すみません、それができなくて苦労しています。
ご回答、ありがとうございました。

お礼日時:2012/04/25 09:35

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