Perl/CGIを使って6つの選択肢からランダムに4つを順に選ぶ(1つも重複せずに選ぶ)コードを教えてください。@kouho=(”A”,”B”,”C”,”D”,”E”,”F”);srand(time|$$);$num=rand(5);$kekka=$kouho[$num];とりあえずここまではできたのですが重複せずに4つを選ぶ方法だけがわかりません。

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2003/07/26 17:56:02
  • 終了:--

回答(9件)

id:alcus No.1

alcus回答回数85ベストアンサー獲得回数02003/07/26 18:06:48

ポイント13pt

このようなプログラムで、配列の中身の順番をばらばらにして、そのなかの先頭4つを取り出してくる。というのが定番かと思います。

特に項目数が 100,1000 と増えてくると実行時間にかなり効いてきます。

id:musa0

@kouho=(”A”,”B”,”C”,”D”,”E”,”F”);

srand(time | $$);

$num=rand(5);

$kekka=$kouho[$num];

ここまでは既にできてます。

重複せずに4つを順に選ぶ方法がわかりません。

2003/07/26 18:14:51
id:sasada No.2

sasada回答回数1482ベストアンサー獲得回数1332003/07/26 18:18:06

ポイント13pt

http://www.hatena.ne.jp/1059209762#

Perl/CGIを使って6つの選択肢からランダムに4つを順に選ぶ(1つも重複せずに選ぶ)コードを教えてください。@kouho=(”A”,”B”,”C”,”D”,”E”,”F”);srand.. - 人力検索はてな

 URLはダミーです。

 以下のスクリプトで如何でしょうか。

=====================================

#!/usr/bin/perl -w

# 要素が削除されるので注意!!

@kouho=(”A”,”B”,”C”,”D”,”E”,”F”);

srand(time|$$);

$times = $#kouho;

for ( $cnt = 0; $cnt < 4 ; ++$cnt ) {

$num=rand($times + 1);

$kekka=$kouho[$num];

print ”KEKKA = {” . $kekka . ”}¥n”;

splice @kouho,$num,1;

$times = $#kouho;

}

=====================================

id:musa0

$times = $#kouho;

は何のためにやっているのでしょうか?また

splice @kouho,$num,1;

$times = $#kouho;

の意味はどういうことでしょうか?重複しないための措置でしょうか?

2003/07/26 18:26:28
id:inokuni No.3

いのくに回答回数1343ベストアンサー獲得回数212003/07/26 18:26:42

ポイント13pt

srand(time|$$);

@array = (”A”, ”B”, ”C”, ”D”, ”E”, ”F”);

@new;

for( @array ){

my $r = rand @new+1;

push(@new, $new[$r]);

$new[$r] = $_;

}

$n = 0;

for( @new ){

print $new[$n].”¥n”;

$n++;

if($n >= 4){

break;

}

}

id:sasada No.4

sasada回答回数1482ベストアンサー獲得回数1332003/07/26 18:33:57

ポイント13pt

http://www.hatena.ne.jp/1059209762?

Perl/CGIを使って6つの選択肢からランダムに4つを順に選ぶ(1つも重複せずに選ぶ)コードを教えてください。@kouho=(”A”,”B”,”C”,”D”,”E”,”F”);srand.. - 人力検索はてな

>$times = $#kouho;

>は何のために

 すみません、慌てて作ったので、修正ミスです。m(_ _)m

 for文の前のその行は削って、for文自体を以下に差し替えてください。

=============================

for ( $cnt = 0; $cnt < 4 ; ++$cnt ) {

$num=rand($#kouho + 1);

$kekka=$kouho[$num];

print ”KEKKA = {” . $kekka . ”}¥n”;

splice @kouho,$num,1;

}

=============================

 spliceは、使用済みの配列要素を削除するのに使用しています。

 一つ選択するごとに、その要素を削除しているので、重複選択されないという仕組みです。

 あと、蛇足ですが、print文は、候補の格納用の処理に置き換えてください。

id:alcus No.5

alcus回答回数85ベストアンサー獲得回数02003/07/26 18:43:01

ポイント13pt

最初の回答とあわせてみてください。

つまり

1. データーを定義して(”ABCDE”)

2. それの順番をばらばらにして(”EADBC”)

3. 頭から必要個数分とってくると、あたかも「重複せずにランダムに4つ選んでいるように見える」という手法です。

あるいは「つかったかどうか」の配列をもういっこ容易して重複を防ぐ方法ですか。

これは最初の回答の説明にも書いたとおり、項目数が多くなるほど時間がかかる可能性があります。(例:99個使用中で残り1個のとき、ランダムに選ぶと”使用中”がでる確立がすごく高い)

id:musa0

後者の方です。

できれば前者の方もお教え願いますか?

2003/07/27 08:34:16
id:jouno No.6

jouno回答回数280ベストアンサー獲得回数02003/07/26 20:27:32

ポイント13pt

え〜と僕のコードが一番汚いと思うんですが。

splice(@card,n,1)で配列のn番目のやつが配列から削除されますで、つぎのを選ぶときは一個少ない数でrandすると。

$a = int(rand(78));

splice(@card,$a,1);

$bxx = int(rand(77));

$b = $card[$bxx];

splice(@card,$bxx,1);

$cxx = int(rand(76));

$c = $card[$cxx];

splice(@card,$cxx,1);

$dxx = int(rand(75));

$d = $card[$dxx];

splice(@card,$dxx,1);

$e= int(rand(74));

$e= $card[$e];

id:musa0

なるほど。

そういうやり方ですか。

これなら僕にも理解できました。

2003/07/27 08:59:16
id:erminus No.7

erminus回答回数33ベストアンサー獲得回数02003/07/27 02:51:56

ポイント14pt

URLはダミーです。

1の回答者の方が書いているように,配列の要素の順列をランダムに入れ替え,先頭の4つの要素を取ることで要件を満たせます。

具体的には,

1. 先頭の要素(インデックス0)を決定する。インデックス1-5からランダムに選択し,インデックス0と交換します。例えば1(B)が選択されるとすると,

A B C D E F -> B A C D E F

となります。

2.2番目の要素(インデックス1)を決定します。1と同様にインデックス2-5からランダムに一つ選択し,インデックス1の要素と交換します。ここで例えば,インデックス5(F)が選ばれたとします。

B A C D E F -> B F C D E A

以下同様に3番目と4番目の要素を決定すれば,重複なく4つの要素をランダムに選択したことになります。

具体的なコードは,

@kouho = (’A’,’B’,’C’,’D’,’E’,’F’);

for $i (0..5) {

$tmp = $kouho[$i];

do {

$num = rand(5);

} while ($num == $i);

$kouho[$i] = $kouho[$num];

$kouho[$num] = $tmp;

}

となります。

id:musa0

for $i (0..5){

とは

for( $i=0 ; $i<5 ; $i++ ){

と同じ意味ですか?

あと

while ($num == $i);

のところで

$num = rand(5);

の$numが5の時はfor文が5で終わるからfor文の0〜4の処理が飛ばされてそのループ処理がいきなり終了してしまいますよね?これだと入れ替えが1回しか行われずに要素0と5だけが入れ替われり、1〜4の要素が入れ替わってないんじゃないですか?

僕自身あまりPerlをわかってないので違っていたらすいません。

2003/07/27 10:00:21
id:erminus No.8

erminus回答回数33ベストアンサー獲得回数02003/07/27 14:14:33

ポイント14pt

URLはダミーです。

7番目の回答者です。説明不足でしたね。

> for $i (0..5){

> とは

> for( $i=0 ; $i<5 ; $i++ ){

> と同じ意味ですか?

同じです。

> $num = rand(5);

> $numが5の時はfor文が5で終わるからfor文

> の0〜4の処理が飛ばされてそのループ処理が

> いきなり終了してしまいますよね?

for文の処理が中断されることはありません。

do 〜 while ($num == $i) の処理を入れているのは,「必ず」要素の交換を行うためです。

例えば,2番目のインデックスを入れ替えたいときに,乱数で2番目のインデックスが選択されてしまうとインデックスが重複するために交換が起こりません。これを防ぐのが目的です。

もちろんこれが無くてもランダムな順列は得られるます。

> これだと入れ替えが1回しか行われずに要素

> 0と5だけが入れ替われり、1〜4の要素が入

> れ替わってないんじゃないですか?

違います。実際に動かしていただければ正しく機能することがお分かりいただけるかと思います。

id:musa0

最後にどれがAでどれがBとかCの結果表示をしたいのですがどういうふうに結果を表示させればいいのでしょう?

$kekka1=$array[0];

$kekka2=$array[1];

$kekka3=$array[2];

としてもエラーが出ました。

forループの中か外どちらに入れればいいのでしょうか?

2003/07/28 10:45:33
id:namwonS No.9

namwonS回答回数10ベストアンサー獲得回数02003/07/28 16:40:32

ポイント14pt

 URLはダミーです。

 差し出がましいかもしれませんが、回答権を使い果たした人の代わりに、私なりに答えてみたいと思います。(嘘八百をいっていたら、ごめんなさい>ALL)

alcusさんへの質問:

>後者の方です。

 これが、「つかったかどうか」の配列をもういっこ容易して重複を防ぐ方法のことでしたら、あっさりコレを選択する人に回答してくれる人はいないと思います。(^^;

>できれば前者の方もお教え願いますか?

 inokuniさんとerminusさんの回答が、これにあたると思います。

erminusさんへの質問:

>forループの中か外どちらに入れればいいのでしょうか?

 外です。

 erminusさんのプログラムの末尾に追加する形で、

$kekka1=$kouho[0]; print ”$kekka1¥n”;

$kekka2=$kouho[1]; print ”$kekka2¥n”;

$kekka3=$kouho[2]; print ”$kekka3¥n”;

$kekka4=$kouho[3]; print ”$kekka4¥n”;

と、入れてみてください。(printは、モニター用です。確認後に削除してください)

 erminusさんのやり方は、かなりスマートです。

 (今回の様に、@kouhoの要素数が充分に少ない事が条件です)

 更にスマートな方法をお望みなら、候補の数だけループを廻すのではなく、結果の数だけループを廻すやり方も有ります。

 イメージとしては、

  (1)トランプの山(候補の配列)からランダムにカード(結果)を抜いて、トランプの山の一番上に置きます。

  (2)上に置いたカード(結果カード)を対象外にして、(1)を必要な回数(結果の数)だけ繰り返します。

  (3)トランプの山の上から順に(結果の数だけ)ランダムなカードが出てきます(これを、結果の配列に格納します)

という感じですね。

 プログラムは、わざと載せません。

 練習を兼ねて、自分で挑戦してみては如何でしょう。(^^)

 必要な情報は、上記回答者のプログラムやリンク先にありそうですよ。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません