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

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]が変数としてない為上記の書き方ではスクリプト自体エラーとなります。

説明が分かりにくい点については申し訳ありませんが、どなたかご教授願えないでしょうか。

よろしくお願いします。

A 回答 (4件)

配列の要素が数値順に並んでいるか否かのチェックは 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 {
# 数値順に並んでいないときの処理
}
    • good
    • 0
この回答へのお礼

丁寧にご教授いただきありがとうございます。

初心者な者で、理解に時間がかかりましたがようやく分かってきました。

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

お礼日時:2010/07/13 12:11

> my $hoge = (1, 10, 100, 50, 1000, 10000, 5000, 100000);



No3 です。すみませんが、1つ記述ミスがありました。以下のように訂正します。

my @hoge = (1, 10, 100, 50, 1000, 10000, 5000, 100000);
    • good
    • 0

文法的なことは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を繰り返さない(一般に,同じことの繰り返しはしない方がいい)
・処理を細切れにして(一個の処理単位はできるだけ短く),
 入口と出口を明確にして,それらをつなぎ合わせる
というようなことです.

具体的なコードはご自分でどうぞ.
「スライス」「ソート」「配列の比較」という
よくある処理の組み合わせです.
    • good
    • 0

配列の要素を使用するときは


$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])
となることがわかります。これは、ループを使って簡単に書くことができます。

この回答への補足

早速ありがとうございます。

>配列の要素を使用するときは
>$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]);
}
のような感じかぁとは思うのですが、ここからどのように比較し真、偽を判別していくかがよく分かりません。

もしよろしければ、簡単にで結構ですので、ループから比較の書き方を教えていただけないでしょうか。

よろしくお願いいたします。

補足日時:2010/07/08 19:24
    • good
    • 0

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