10個の配列から被らないように5つの値を取りだす

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
テントウムシ

10個の配列から被らないように5つの値を取りだす

#1

投稿記事 by テントウムシ » 15年前

10個の配列から被らないようにランダムに5つの値を取りだしたいです。
下記の様なソースを考えてみたのですが""の部分の書き方がわかりません・・・。
 ※わからないというより ==&&と複数書かなければいけないのでしょうか?
もっと効率のよいPGはないでしょうか?
int Num[10] = { 1,2,3,4,5, 6,7,8,9,10 };
int Array[5];

while(1){
    for(int i=0; i<5; i++){
        Array = rand()%10;
    }
    if("全部違ってたら")break;
}

たかぎ

Re:10個の配列から被らないように5つの値を取りだす

#2

投稿記事 by たかぎ » 15年前

std::random_shuffleでかき混ぜたあと、最初から5つを取り出せばOKです。

MNS

Re:10個の配列から被らないように5つの値を取りだす

#3

投稿記事 by MNS » 15年前

一応、for文を重ねることによって
while(1){
for(int i=0; i<5; i++)
{
Array = rand()%10;
}
for(int x=0; x<5; ++x)
{
for(int y=0; y<5; ++y)
{
if(x!=y && Array[x]==Array[y])
{
goto CONTINUE;
}
}
}
break;
CONTINUE:
continue;
}
と書くことも出来ますが、効率は良くないでしょう。スマートでもありませんね。
それよりは、たかぎさんが仰るような、
そもそも値が重複しないように取り出す手法をとったほうが無難です。

シエル

Re:10個の配列から被らないように5つの値を取りだす

#4

投稿記事 by シエル » 15年前

簡単に作ってみました。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main(void)
{
int Num[10] = { 1,2,3,4,5, 6,7,8,9,10 };
int random[5];
int tmp;
int j;

srand((unsigned)time(NULL));

for(int i=0;i<5;i++){
random=0;
while(1){
tmp=rand()%10;
for(j=0;j<i+1;j++){
if(random[j]==tmp){
break;
}
}
if(j==i+1){
random=tmp;
break;
}
}
}

for(int s=0;s<5;s++){
printf("ランダム数字=%d\n",random);
}
for(int x=0;x<5;x++){
printf("配列の数字読み込み=%d\n",Num[random[x]]);
}
} 画像

ideyan

Re:10個の配列から被らないように5つの値を取りだす

#5

投稿記事 by ideyan » 15年前

while(1)に対抗して(笑)
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 }; 
int Array[5]; 
int i=0,j=0,tmp;
srand((unsigned)time(NULL)); 
    
while(i<5){
    tmp = rand()%10;
    for(j=0;j<i;++j){
        if(Array[j]==Num[tmp])break;
    }
    if(j==i){
        Array=Num[tmp];
        ++i;
    }
}


でもやってることは皆さんと変わらないw
最初から被らないようにするのがいいですよねぇ。

シエル

Re:10個の配列から被らないように5つの値を取りだす

#6

投稿記事 by シエル » 15年前

ideyanさんに横槍を入れるようで申し訳ないですが、
ideyanさんのコードだとNumの配列内に同じ数字があった場合は
その数字は一回しか選ばれない気がします。

間違ってたらすいません。

ideyan

Re:10個の配列から被らないように5つの値を取りだす

#7

投稿記事 by ideyan » 15年前

ん、あぁ。
元々の配列も重複無しかと思ってたんですが
よく見たら特にそんなことは書いてないですね^^;

というわけで修正版。
欠点は配列の要素の数と同じ個数のバッファを必要とすることです。
(同じ長さである必要は無いですがビット演算面倒です。。。)
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 }; 
char flag[10];
int Array[5]; 
int i=0,tmp;

srand((unsigned)time(NULL)); 
for(i=0;i<10;++i)flag=0;

i=0;
while(i<5){
    tmp = rand()%10;
    if(!flag[tmp]){
        flag[tmp]=1;
        Array[i++]=Num[tmp];
    }
}

めるぽん

Re:10個の配列から被らないように5つの値を取りだす

#8

投稿記事 by めるぽん » 15年前

たかぎさんの書いているのが一番スマートが気がしますね。

#include <algorithm>
#include <iostream>

int main()
{
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 };
int Array[5];
std::random_shuffle(Num, Num + 10);
std::copy(Num, Num + 5, Array);

for (int i = 0; i < 5; i++) std::cout << Array << std::endl;
}

もし元の配列に重複する値があるなら、std::sort して std::unique で削除してしまえばいいかと。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <cassert>

int main()
{
int Num[10] = { 8,2,3,2,4,5,1,5,8,9 };
int Array[5];
std::sort(Num, Num + 10);
int* last = std::unique(Num, Num + 10);
assert(std::distance(Num, last) >= 5); // 5個以上は unique な値が必要
std::random_shuffle(Num, last);
std::copy(Num, Num + 5, Array);

for (int i = 0; i < 5; i++) std::cout << Array << std::endl;
}

閉鎖

“C言語何でも質問掲示板” へ戻る