Perlの比較、ループの使い方について質問

このQ&Aのポイント
  • Perlの比較、ループの使い方について質問です。perlの初心者でperlを使っていろいろと勉強しているのですが、簡単に書ける方法はないでしょうか?
  • 質問者はPerl初心者であり、比較やループの方法について簡単な書き方を知りたいと述べています。具体的な要件として、指定された数値の配列要素を比較し、条件に合わない場合にエラーを出力したいとのことです。
  • さらに、現在のコードではエラーが出力されず、正常な動作ができていないと報告しています。この問題の解決策も求められています。
回答を見る
  • ベストアンサー

perlの比較、ループの使い方について質問です。

perlの比較、ループの使い方について質問です。 perlの初心者でperlを使っていろいろと勉強しているのですが、以下のような場合、簡単に書ける方法ってないでしょうか? 比較、ループなど調べてみたのですが、なかなか思うようにいきません。 よろしくお願いします。 なお、以下のスクリプトではエラーが出て動きませんが、その点は今回の説明の為ご了承願います。 my @hoge(1,10,100,1000,10000,100000,1000000); my $no=☆ ←☆については1~5の間でランダムに設定します。 my(@test); for (my $i=0; $i<$no; $i++) { @test[$i]=@hoge[$i]; } 例えば$noが2の場合、@test[0]と@test[1]を比較(@test[0]<@test[1])して偽の場合は、エラーを出し、$noが3の場合、@test[0]と@test[1]と@test[2]を比較(@test[0]<@test[1]<@test[2])して偽の場合は、エラーを出し、$noが4の場合、@test[0]と@test[1]と@test[2]と@test[3]を比較(@test[0]<@test[1]<@test[2]<@test[3])して偽の場合は、エラーを出し……以下同じような感じで進めたいのですが、簡単な書き方ってないでしょうか? if ($no==2){ unlss (@test[0]<@test[1]){エラー} }elsif($no==3){ unless (@test[0]<@test[1]<@test[2]){エラー} }elsif($no==4){ unless (@test[0]<@test[1]<@test[2]<@test[3]){エラー} } 上記のような書き方となるかと思いますが、$noが2の場合、test配列に@test[2]と@test[3]が変数としてない為上記の書き方ではスクリプト自体エラーとなります。 説明が分かりにくい点については申し訳ありませんが、どなたかご教授願えないでしょうか。 よろしくお願いします。

  • hana43
  • お礼率49% (105/212)
  • Perl
  • 回答数4
  • ありがとう数6

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

  • ベストアンサー
  • kumoz
  • ベストアンサー率64% (120/185)
回答No.3

配列の要素が数値順に並んでいるか否かのチェックは grep を使って行うことができます。次のコードは、すべての隣接する要素を数値比較し、直前の要素よりも小さい要素の添字を @small に入れるものです。 my $hoge = (1, 10, 100, 50, 1000, 10000, 5000, 100000); my @small = grep { $hoge[$_ - 1] > $hoge[$_] } 1 .. $#hoge; print "$hoge[$_ -1] > $hoge[$_]\n" foreach @small; 範囲演算子の両側の数値を変えれば、部分配列もチェックできます。1 .. 3 とすれば先頭の4つを、3 .. 5 とすれば添字 2 から 5 までをチェックできます。また、grep は if や unless 条件部に置くことができます。次のコードは、$hoge[0] < $hoge[1] < $hoge[2] と同等の効果が得られます。 unless (grep { $hoge[$_ - 1] >= $hoge[$_] } 1 .. 2) { # 数値順に並んでいるときの処理 } else { # 数値順に並んでいないときの処理 }

hana43
質問者

お礼

丁寧にご教授いただきありがとうございます。 初心者な者で、理解に時間がかかりましたがようやく分かってきました。 ありがとうございました。

その他の回答 (3)

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.4

> my $hoge = (1, 10, 100, 50, 1000, 10000, 5000, 100000); No3 です。すみませんが、1つ記述ミスがありました。以下のように訂正します。 my @hoge = (1, 10, 100, 50, 1000, 10000, 5000, 100000);

  • kabaokaba
  • ベストアンサー率51% (724/1416)
回答No.2

文法的なことはNo.1さんのご指摘の通りですが・・・・ たぶんきちんとした書籍を読んだ方がいいです. ぜったいこんな書き方しない!っていう書き方が散見できますので #my(@test) なんて普通は書かない・・・ #意図的にわざとすることがないとは言わないけど 次に,きちんと処理手順を考えましょう 要は $no の値に応じて,異なるものを比較して結果を出したいということでしょう $no=2 => $test[0]<$test[1] $no=3 => $test[0]<$test[1]<$test[2] という具合に($no=1の場合のチェックは?). となると, (1) $noに応じて,比較対象を取り出す (2) 取り出した比較対象を実際に比較する (1)については配列の「スライス」をすればいいでしょう. 配列@testの0..$no-1の要素を取り出せばOK (2)については@testの各要素が数字であるという条件で 今回のように「順番」であることを求めるならば ソートを使えばいいでしょう. @testの0..$no-1でできた配列の要素と,それを昇順で並べた配列の要素が 順番も含めて完全に一致していればクリア,そうでなければアウト #この処理だと$noのときは常にクリアとなる ついでにいえば,質問に書かれていることだけなら @hogeからわざわざ@testをコピーする必要はないでしょう? @hogeをそのまま使えばOKでは? アルゴリズムの一例をあげました. こういうののコツは ・if-elseを繰り返さない(一般に,同じことの繰り返しはしない方がいい) ・処理を細切れにして(一個の処理単位はできるだけ短く),  入口と出口を明確にして,それらをつなぎ合わせる というようなことです. 具体的なコードはご自分でどうぞ. 「スライス」「ソート」「配列の比較」という よくある処理の組み合わせです.

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

配列の要素を使用するときは $test[0] と$を使うのが普通。 @test[0]は 0番目の要素からなるリスト。 この違いは場合によっては結構重要。 > $test[0]<$test[1]<$test[2] Perlではこのような条件式の書き方はゆるされていません。 このような数学的な書き方は、プログラミング言語によって 1)そもそも文法エラーになる 2)書けるけど実行時にエラー 3)書けるけど意味が違う: a<b<c→a<bの真偽を表す値と cの比較(真偽が1/0なら 1<c または 0<c) 4)数学と同じ意味 となり、Perlでは1)、C言語では3)で、4)という言語はほとんどありません。 syntax error at XXX.pl line XX, near "] <" とかいうエラーメッセージではなかったですか?(こちらではそうなりました) これは「文法(syntax)間違い(error)」です。 >@test[2]と@test[3]が変数としてない為 のエラーではありません。そもそもPerlでは、使用してない添字を指定してもエラーは出ません。 a<b<c → a<b かつ b<c という意味を明確に指定する必要があります ($test[0]<$test[1]) && ($test[1]<$test[2]) こう分けて考えれば ($test[0]<$test[1]) ($test[1]<$test[2]) ... ($test[i-1]<$test[i]) .... ($test[n-1-1]<$test[n-1]) となることがわかります。これは、ループを使って簡単に書くことができます。

hana43
質問者

補足

早速ありがとうございます。 >配列の要素を使用するときは >$test[0] と$を使うのが普通。 >@test[0]は 0番目の要素からなるリスト。 >この違いは場合によっては結構重要。 @を使っても$を使っても同じ事だと思ってたので、普通に@を使ってましたが…。 今後は$を使うようにします。 >$test[0]<$test[1]<$test[3] こちらが文法エラーだったとは…。勉強不足です。 教えていただきありがとうございます。 >a<b<c → a<b かつ b<c >という意味を明確に指定する必要があります >($test[0]<$test[1]) && ($test[1]<$test[2]) >こう分けて考えれば >($test[0]<$test[1]) >($test[1]<$test[2]) >... >($test[i-1]<$test[i]) >.... >($test[n-1-1]<$test[n-1]) >となることがわかります。これは、ループを使って簡単に書くことができます。 ($test[i-1]<$test[i])までは分かるのですが(例えば私が示した$i=2の場合, $test[1]<$test[2]となる)、($test[n-1-1]<$test[n-1])のnとはどのような場合なのでしょうか。 またループについてですが、 for (1..3){ ($test[i-1]<$test[i]); } のような感じかぁとは思うのですが、ここからどのように比較し真、偽を判別していくかがよく分かりません。 もしよろしければ、簡単にで結構ですので、ループから比較の書き方を教えていただけないでしょうか。 よろしくお願いいたします。

関連するQ&A

  • Perlの書き方について

    perlを勉強していて、似たような配列やハッシュの場合でしたらなんとか解決出来たのですが、以下の場合が思うような結果が得られず困っているので、どなたか教えていただきたく質問しました。 例) my $hoge1=10; my $hoge2=9; my $hoge3=8; my $hoge4=7; my $hoge5=6; my $hogehoge; for(1..5){ $hogehoge+=$hoge$_; } 上記の書き方の場合、「$hoge$_」でエラーが出ます。 このような場合は、どのように書けばいいのでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • perlでcheckboxがうまく整理できない

    perl5.8でFormから送られてきたデータを取得し、整理しています。 FormはPOSTでperlに送り、データを整理したのですが、checkboxで複数のデータを送ったとき、うまく処理されていません。 Formのあるページも同じperlでcgiページを作り、エラーがあった場合、エラーメッセージ付きで再度そのcgiページを表示するようにしています。 次の内容で、@noにcheckboxで選択した番号が入るようにしています。 valueには - が余分にありますが、これは試しにcheckboxで複数選択してデータをsubmitしてみたところ、受け取り先の$in{no}で番号が連続して1つのスカラーで連なるので、番号を後に分割するために-を入れ、受け取り後、@no = split(/-/, $in{no});でばらして@noに番号を格納してあります $r_noは別のデータから受け取った比較先の番号です Formのcheckboxの部分は(実際はこれを複数回ループして$r_noが変化します) my $checkbox; foreach my $l (@no){ my $i = 0; if($l == $r_no){ $i = 1; } if($l == $r_no){ $checkbox = "<input type=\"checkbox\" name=\"no\" value=\"$r_no-\" checked>"; last; }else{ $checkbox = "<input type=\"checkbox\" name=\"no\" value=\"$r_no-\">"; } } print "$checkbox"; 2つ以上checkboxを選択して、わざとエラーが出るように他の部分を間違った選択をするようにして試してみたところ、@noには選択した分だけの番号が格納されているにもかかわらず、 if($l == $r_no){ の部分が真になるのは1つ目の@noとの真偽だけで、2つ目以降は本来真になるべき比較でも偽になってしまいます。 改行コードなどが入っているのかと思い、chompで後ろを削ったり、$l =~ s/\r?\n/K/g; $l =~ s/\r/K/g;で改行コードを可視化して確認してみましたが、それらしきものも入っていませんでした @noには選択した番号全てが収納されていますし、後ろに改行コードなど不要なものも入ってないのに真偽の分岐がうまくいかない原因は何にあるのでしょうか? 思い当たるものは一通り試したのですが、どうしてもわかりません。 「これが原因かも?」みたいな可能性だけでも結構ですので教えてください。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンの引数引継ぎ?

    こんにちは。 Perlの引数について質問です。 サブルーチンに引数を渡し、サブルーチンの中で他のサブルーチンをよんでいます。 すると引数を渡していないサブルーチンにまで引数が与えられてしまっているようです。 @_で受け取ると引数が渡されてしまい、$_[0]だと渡されずにすみます。 これはなぜなのでしょうか?Perlには引数を引き継ぐルールでもあるのでしょうか? 以下、サンプルです。 -------------------------------- &test('引数です'); sub test { &test2; } sub test2 { (my $hoge) = @_; } -------------------------------- $hogeに「引数です」が入ります。 &test2;を&test2();とすると大丈夫です。

    • ベストアンサー
    • Perl
  • kshでのNULLの比較

    以下のスクリプトを作成し、変数に格納された値がNULLか調べたいと思っていますが、エラーが出力されてしまいます。 ■スクリプトの中身 #!/usr/bin/ksh HOGE="" if [ ${HOGE} != "" ]; then echo "${HOGE}" fi if [ -n ${HOGE} ]; then echo "${HOGE}" fi ■エラー + HOGE= + [ != ] hoge[5]: test: 0403-004 このコマンドにはパラメーターを指定してください。 + [ -n ] hoge[8]: test: 0403-004 このコマンドにはパラメーターを指定してください。 変数の中身がnullの場合、どのような比較条件を記述すればよいのでしょうか?

  • PERLの「!=」と「=~」 or 「if」と「unless」必ずしも真反対の意味ではない?

    下記コードは、同じ意味だと思っていたのですが、 実行すると違った結果が表示されます。 何故でしょうか? my $string = 'A-test'; unless($string =~ m/-Hoge/){print '=~>',$string;} if($string != m/-Hoge/){print '!=>',$string;}

    • ベストアンサー
    • Perl
  • ループ内での置換方法について

    ループ内での置換方法について 以下の内容で置換を行ってみたのですが、書き方が悪いのかうまく取得できません。 $hoge="現在のナンバーは《no》です"; for(1..3){ $hoge=~s/《no》/$_/g; print"$hoge<br>"; } 結果、noの部分は全て1となりました。 私の予定では、1、2、3と順に表示される予定でしたが・・・。 現在のナンバーは1です 現在のナンバーは2です 現在のナンバーは3です と表示されるようにするにはどのように書けばよろしいでしょうか。 どなたか教えていただけませんか。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • perlで比較関数を使ったソートの仕方

    今、季節をソートするようなプログラムを考えています。 my @array = ('spring','fall','winter','summer'); my @sort = sort number(@array); sub number { if ($a < $b) { return -1; } elsif ($a == $b) { return 0; } elsif ($a > $b) { return 1; } } 実行結果:spring ,summer ,fall ,winter 比較関数を使用して、「春・夏・秋・冬」とソートできるようにしたいです。上のプログラムはまだ途中なんですが、この場合比較関数はどのように実装すればうまくソートできるんでしょうか?分かる方、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ループ中でのmy宣言と処理速度

    こんにちは、Perl入門者ですがよろしくお願いします。 質問内容はループ中にmy宣言をいちいちすると処理速度は落ちてしまうのかということです。 ソースを例に挙げると まず、$lenをループの外に書く方法と my $i; my $len; for( $i=0 ; $i<1024 ; $i++){ $len = length($str[$i]; } $lenをループの中に書く方法 my $i; for($i=0 ; $i<1024 ; $i++){ my $len; $len = length($str[$i]); } の2種類です(その他の変数については特に言及していません) 使いやすさでいえば、ループ内で宣言をした方が自動的に初期化されるのでうれしいのですが ふと、いちいちメモリの解放と確保を行っているわけですからOS(?)に負荷がかかって遅くなっているのではと考えました。 Perlで処理速度を測ることもできるようですが恥ずかしいながらスキル不足です。すいません。 どなたかご存知の方、自分なりの考えがある方はご教授頂きたく存じます。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • perl 配列名変数指定するには

    perlプログラムで for文で ループ分の配列定義するには どうしたらよいですか? 下記のようなことができないかと 考えております。 for(my $i = 0; $i < $file_no; $i++){ my @{"segments$i"} =(); #配列定義 my ${"line$i"}="";     #変数定義 my %{"hash$i"}= ();    #ハッシュ定義 open(ARG1,$ARGV[$i]); while(<ARG1>){ ${'line'.$i} = $_; chomp ${'line'.$i}; @{'segments'.$i} = split(/\t/,${'line'.$i});        ${'hash'.$i}{${'segments'.$i}[0]}=${'segments'.$i}[1];     } close(ARG1); } #下記で、その後 各ハッシュに設定したデータをもとに いろいろ計算したい foreach my $a (keys %{'hash'.$i}){ ・・・ } 今は、Can't declare array dereference in "my" at test.pl line XX, near "} =" と 配列定義でエラーとなり処理できません。

    • ベストアンサー
    • Perl
  • PHP プログラム ループ処理

    プログラム初心者です、ループ処理についてうまい解決方法が思い浮かばず相談させて頂きます。 ループ処理において、ループ内で変数を定義するのに違う名前を指定するにはどのような方法があるのでしょうか 例えばwhileの場合 $i =0; while($i<10){ $hoge = $i; $i++ } この$hogeを2順目には$hoge1、3順目には$hoge2と言うように増やしたり一定の法則に乗っ取って変数名を変更するにはどのように書けばいいのでしょうか。 どなたかご教授頂ければと存じます、宜しくお願い致します。

    • ベストアンサー
    • PHP

専門家に質問してみよう