3種類の文字列を入れた配列を2つ用意し、3つに分配する際に
・絶対にかぶってはいけない
・各文字列2つまでなので
ジュースとアメ
ジュースとチョコ
ジュースとアメ
というのは不可能
こういったものを書くにはどこを改善すればいいのでしょうか?
JavaScript
1<!doctype html> 2<html> 3<head> 4 <meta charset="utf-8"> 5 <title></title> 6</head> 7<body> 8 9<script> 10 11 var menu1 = ["ジュース","チョコ","アメ"]; 12 var menu2 = ["ジュース","チョコ","アメ"]; 13 14 for(var i = 0; i < 3; i++){ 15 //menuのrandom 16 var rnd1 = Math.floor(Math.random() * menu1.length); 17 var rnd2 = Math.floor(Math.random() * menu2.length); 18 console.log(menu1[rnd1] + "と" + menu2[rnd2]); 19 } 20 21</script> 22</body> 23 24</html>
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2015/08/24 02:11

回答5件
0
この問題は3つの要素を持つ配列から無作為に2つの要素を得るのと同じだと思います。
組み合わせは3通りなので同じ組み合わせを許さない要件であれば組み合わせを求めるだけで完了しますが、要件上は同じ組み合わせを複数回出力する事も可能なようです(["ジュース", "アメ"]
を3回出力しても良い)。
方法としては3つ考えられますが、いずれも用意する配列は一つで済みます。
(方法1) 配列をシャッフルし、index
が 0
, 1
の要素を取り出す処理を3回繰り返す
(方法2) 元の配列から2つの要素を取り出す組み合わせとなる配列を生成し、組み合わせ配列から無作為に一つ選ぶ処理を3回繰り返す
(方法3) 前方法で求めた組み合わせ配列1から3回無作為に選ぶ組み合わせ配列2を用意し、組み合わせ配列をシャッフルして index
が 0
の要素を出力する
ここでは (方法2) を使ってコードを書きます。
JavaScript
1function createPairPatternAll (array) { 2 var pairPatterns = []; 3 4 for (var i = 0, l = array.length, element; i < l; ++i) { 5 for (var j = i + 1, element = array[i]; j < l; ++j) { 6 pairPatterns.push([element, array[j]]); 7 } 8 } 9 10 return pairPatterns; 11} 12 13function getPairs (array, size) { 14 var pairPatterns = createPairPatternAll(array), 15 l = pairPatterns.length, 16 pairs = []; 17 18 if (arguments.length < 2) { 19 size = 1; 20 } 21 22 while (size--) { 23 pairs.push(pairPatterns[Math.floor(Math.random() * l)]); 24 } 25 26 return pairs; 27} 28 29console.log(getPairs(['ジュース', 'チョコ', 'アメ'], 3)); // [['チョコ', 'アメ'], ['チョコ', 'アメ'], ['ジュース', 'アメ']]
console.log()
は Chrome Developer Tools を使えば確認できます。
Google Chrome 以外のブラウザにも同様の機能があります。
投稿2015/08/23 14:29
編集2015/08/23 14:33総合スコア18194
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
menu1 = ["ジュースA","チョコA","アメA"]
menu2 = ["ジュースB","チョコB","アメB"]
と捉え、
0. menu1、menu2から各要素は1度しか取り出されない。
0. menu1、menu2の要素の名前ではなく、取り出し順が同じにならない。
という方法で、取得する方法を書いてみます。
※ 2の条件から menu2 = ["チョコB","ジュースB","アメB"] とした場合は
ジュースA と ジュースB
の様に取り出されてしまいます。
各処理をわかり易く書こうと思ったら、
すごく冗長なコードになってしまったので、かなりリファクタリング出来ると思います。
javascript
1var menu1 = ["ジュースA","チョコA","アメA"]; 2var menu2 = ["ジュースB","チョコB","アメB"]; 3 4// 配列の長さが違うと死ぬので同じにする 5var adjustLength = function(arg1, arg2) { 6 var l1 = arg1.length, 7 l2 = arg2.length, 8 gap = Math.abs(l1 - l2), 9 adjustArg; 10 if(gap) { 11 adjustArg = (l1 > l2)? arg2 : arg1; 12 for(var i=0; i<gap; i+=1) { 13 adjustArg[ adjustArg.length ] = "なし!"; 14 } 15 } 16}; 17 18// 取り出し方のパターンを作成 19var getRandomPattern = function(n) { 20 var arg = [], 21 patterns = []; 22 for(var i=0; i<n; i+=1) { 23 arg[i] = i; 24 } 25 26 var generatePattern = function(tmp, post, n) { 27 if(n > 0) { 28 var next, rest; 29 for(var i=0, l=post.length; i<l; i+=1) { 30 rest = post.slice(0); 31 next = rest.splice(i, 1); 32 generatePattern(tmp.concat(next), rest, n-1); 33 } 34 } else { 35 console.log(tmp); 36 patterns[ patterns.length ] = tmp; 37 } 38 } 39 console.log('▼ 取り出し順の全パターン ▼'); 40 generatePattern([], arg, arg.length); 41 return patterns; 42}; 43 44!function() { 45 var i = 0, 46 l = 0, 47 patterns, 48 rand1, 49 rand2, 50 ptn1, // menu1 の取り出し順 51 ptn2, // menu2 の取り出し順 52 isSame = true; 53 54 adjustLength(menu1, menu2); 55 patterns = getRandomPattern( menu1.length ); 56 rand1 = Math.floor( Math.random() * patterns.length ); 57 ptn1 = patterns.splice(rand1, 1)[0]; 58 while(isSame) { 59 rand2 = Math.floor( Math.random() * patterns.length ); 60 ptn2 = patterns.splice(rand2, 1)[0]; 61 isSame = false; 62 for(i=0, l=ptn1.length; i<l; i+=1) { 63 // 取り出し順の値が被らないかチェック 64 if(ptn1[i] === ptn2[i]) { 65 isSame = true; 66 break; 67 } 68 } 69 } 70 console.log('▼ menu1, menu2 それぞれの取り出し順 ▼'); 71 console.log(ptn1, ptn2); 72 73 console.log('▼ 決まった取り出し順に基いて順番に取り出す ▼'); 74 for(i=0, l=ptn1.length; i<l; i+=1) { 75 var m1 = menu1[ ptn1[i] ], 76 m2 = menu2[ ptn2[i] ]; 77 console.log(m1 + 'と' + m2); 78 } 79}();
要素名で被らないようにするのであれば、下記で上手く取り出せそうな気がします。
0. menu1、menu2のそれぞれの並び順のパターンを作成
0. ランダムに並び順のパターンを取得
0. 同じ取り出し順に同じ値があったら2をやり直し
0. ループで各配列の並び順に出力
javascript
1var menuA = ["ジュース","チョコ","アメ"]; 2var menuB = ["チョコ","ジュース","アメ","バナナ"]; 3 4// 配列の長さを同じにする 5var adjustLength = function(arg1, arg2) { 6 var l1 = arg1.length, 7 l2 = arg2.length, 8 gap = Math.abs(l1 - l2), 9 adjustArg; 10 if(gap) { 11 adjustArg = (l1 > l2)? arg2:arg1; 12 for(var i=0; i<gap; i+=1) { 13 adjustArg[ adjustArg.length ] = "なし!"; 14 } 15 } 16}; 17 18// 配列の並び順のパターンを作成 19var generatePatterns = function(arg) { 20 var patterns = []; 21 var sortArg = function(allPtns, ptnArg, post, n) { 22 if(n > 0) { 23 var next, rest; 24 for(var i=0, l=post.length; i<l; i+=1) { 25 rest = post.slice(0); 26 next = rest.splice(i, 1); 27 sortArg(allPtns, ptnArg.concat(next), rest, n-1); 28 } 29 } else { 30 console.log(ptnArg); 31 allPtns[ allPtns.length ] = ptnArg; 32 } 33 }; 34 sortArg(patterns, [], arg, arg.length); 35 return patterns; 36}; 37 38!function() { 39 var i = 0, 40 l = 0, 41 allPatternsA, 42 allPatternsB, 43 randA, 44 randB, 45 ptnA, 46 ptnB, 47 isSame = true; 48 49 adjustLength(menuA, menuB); 50 console.log('▼ menuAの取り出し方の全パターン ▼'); 51 allPatternsA = generatePatterns(menuA); 52 console.log('▼ menuBの取り出し方の全パターン ▼'); 53 allPatternsB = generatePatterns(menuB); 54 55 randA = Math.floor( Math.random() * allPatternsA.length ); 56 ptnA = allPatternsA[randA]; 57 while(isSame) { 58 randB = Math.floor( Math.random() * allPatternsB.length ); 59 ptnB = allPatternsB[randB]; 60 isSame = false; 61 for(i=0, l=ptnA.length; i<l; i+=1) { 62 // 取り出し順の値が被らないかチェック 63 if(ptnA[i] === ptnB[i]) { 64 isSame = true; 65 break; 66 } 67 } 68 } 69 console.log('▼ menuA, menuB それぞれの取り出し順 ▼'); 70 console.log(ptnA, ptnB); 71 72 console.log('▼ 決まった取り出し順に基いて順番に取り出す ▼'); 73 for(i=0, l=ptnA.length; i<l; i+=1) { 74 var m1 = ptnA[i], 75 m2 = ptnB[i]; 76 console.log(m1 + 'と' + m2); 77 } 78}();
追記
下記の手順で取り出す方法を追記します。
0. menu1をシャッフルするして順番を入れ替える
0. menu2をシャッフルする
0. インデックス順に各配列の要素を取り出してチェック。1回でも値が同じ場合があると2をやり直し
0. インデックス順に各配列の要素を取り出す
javascript
1var menu1 = ["ジュース","チョコ","アメ"]; 2var menu2 = ["ジュース","チョコ","アメ"]; 3var sameFlg = true; 4 5// fisher-yates アルゴリズム 6// katoyさんの書かれている配列をシャッフルする方法 7var shuffle = function(arg) { 8 var i, j, l, tmp; 9 for(l=arg.length, i=l-1; i>0; i-=1) { 10 j = Math.floor(Math.random() * (i+1)); 11 tmp = arg[i]; 12 arg[i] = arg[j]; 13 arg[j] = tmp; 14 } 15 return arg; 16}; 17 18// menu1をシャッフル 19menu1 = shuffle(menu1); 20 21while(sameFlg) { 22 // menu2をシャッフル 23 menu2 = shuffle(menu2); 24 // 順番に取り出して同じ値が出てくる時はmenu2のシャッフルをやり直す 25 sameFlg = false; 26 for(var i = 0, l = menu1.length; i<l; i+=1) { 27 if(menu1[i] === menu2[i]) { 28 sameFlg = true; 29 break; 30 } 31 } 32} 33 34console.log('▼ menu1, menu2 それぞれの取り出し順 ▼'); 35console.log(menu1, menu2); 36for(var i = 0, l = menu1.length; i<l; i+=1) { 37 console.log(menu1[i] + " と " + menu2[i]); 38}
いずれにせよ
A. menu1のジュース
とmenu2のジュース
を区別する
= それぞれの袋の中から1つづつ取り出しす かつ 取り出されたモノ(の種類)が被らないようにする
B. ジュース
というも区別できないモノのが2つ有るとする
= 大きな袋に全部入れてランダムに2つ取り出して、取り出されたモノが被らないようにする
のどちらかによってコードは変わってくると思います。
私が書いたのはいずれも、A. の考え方の場合です。
投稿2015/08/23 06:41
編集2015/08/23 13:19総合スコア596
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
質問文が求めている生成するメニューの制約制限がよくわかりません。
とりあえず、 menu1, menu2 から1つずつ選んで、すべての品物を3つに分配するという制限で
書いてみました。
ここでは、
menu1, memu2 をそれぞれ シャッフルして、
(menu1[0], menu2[0])
(menu1[1], menu2[1])
(menu1[2], menu2[2])
として、3つに分配しました。
javascript
1// See http://garafu.blogspot.jp/2015/02/javascript_15.html 2// 配列をシャッフルする。 3function shuffle(arr) { 4 var i, j, tmp, length; 5 for (length = arr.length, i = length - 1; i > 0; i--) { 6 j = Math.floor(Math.random() * (i + 1)); 7 tmp = arr[i]; 8 arr[i] = arr[j]; 9 arr[j] = tmp; 10 } 11 return arr; 12} 13 14var menu1 = ["ジュース","チョコ","アメ"]; 15var menu2 = ["ジュース","チョコ","アメ"]; 16 17menu1 = shuffle(menu1); 18menu2 = shuffle(menu2); 19for (var i = 0; i < 3; i++) { 20 console.log(menu1[i] + " と " + menu2[i]); 21}
配列のシャッフルについては、teratail でも過去に質問が出ています。
投稿2015/08/23 03:12
総合スコア22328
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
使った物を覚えておくしかないですね。
JavaScript
1var menu1 = ["ジュース","チョコ","アメ"]; 2var menu2 = ["ジュース","チョコ","アメ"]; 3var shown = {} 4 5var i = 0; 6while( i < 3 ){ 7 //menuのrandom 8 var rnd1 = Math.floor(Math.random() * menu1.length); 9 var rnd2 = Math.floor(Math.random() * menu2.length); 10 var msg = menu1[rnd1] + "と" + menu2[rnd2]; 11 if( shown[msg] ) continue; 12 i++; 13 shown[msg] = true; 14 console.log(msg); 15}
投稿2015/08/23 01:11
総合スコア86295
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/08/23 06:46

0
何かしらの方法で重複チェックが必要ですね。
例えば、連想配列使って使用済みかチェックするとか...
Java
1 var menu1 = ["ジュース","チョコ","アメ"]; 2 var menu2 = ["ジュース","チョコ","アメ"]; 3 var used = []; 4 5 for(var i = 0; i < 3;){ 6 //menuのrandom 7 var rnd1 = Math.floor(Math.random() * menu1.length); 8 var rnd2 = Math.floor(Math.random() * menu2.length); 9 10 if (rnd1 == rnd2) { 11 continue; 12 } 13 14 var key = ((1 << rnd1) | (1 << rnd2)); 15 if (used[key] == true) { 16 continue; 17 } 18 19 console.log(menu1[rnd1] + "と" + menu2[rnd2]); 20 used[key] = true; 21 i++; 22 }
投稿2015/08/23 01:10
総合スコア490
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/08/23 06:45

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。