質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

5回答

4403閲覧

JavaScriptでかぶらないように変数を分配したい

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2015/08/23 00:29

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katoy

2015/08/23 08:14

入力する menu1, menu2 の条件を明確にしてください。 例: 長さはどちらも 3 固定なのか、 固定ではないが、 menu1 と menu2 の長さは同じでなければならないのか、 2つののメニューの長さは無関係でなんでもよいのか? 出力するメニュー 3 つの生成方法と、制約条件を明確にしてください。 2つ以上の正しい生成例を含めてください。2つ以上の不正な生成例を含めてください。それらには不正理由も記載してください。
退会済みユーザー

退会済みユーザー

2015/08/24 02:11

ジュース、チョコ、アメの引換券が2枚ずづあるとします それを3人の子どもに均等に分配します その時にジュースとジュース、アメとアメと言った同じものを二枚渡すのはダメだということです
guest

回答5

0

この問題は3つの要素を持つ配列から無作為に2つの要素を得るのと同じだと思います。
組み合わせは3通りなので同じ組み合わせを許さない要件であれば組み合わせを求めるだけで完了しますが、要件上は同じ組み合わせを複数回出力する事も可能なようです(["ジュース", "アメ"] を3回出力しても良い)。
方法としては3つ考えられますが、いずれも用意する配列は一つで済みます。

(方法1) 配列をシャッフルし、index0, 1 の要素を取り出す処理を3回繰り返す
(方法2) 元の配列から2つの要素を取り出す組み合わせとなる配列を生成し、組み合わせ配列から無作為に一つ選ぶ処理を3回繰り返す
(方法3) 前方法で求めた組み合わせ配列1から3回無作為に選ぶ組み合わせ配列2を用意し、組み合わせ配列をシャッフルして index0 の要素を出力する

ここでは (方法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
think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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
KiKiKi_KiKi

総合スコア596

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KiKiKi_KiKi

2015/08/23 12:16

各配列の取り出し方のバリデーションを全部列挙するより 1. 配列Aをシャッフルするして順番を入れ替える 2. 配列Bをシャッフルする 3. インデックス順に各配列の要素を取り出してチェック。1回でも値が同じ場合があると2をやり直し 4. インデックス順に各配列の要素を取り出す が一番コード数少なくて済みそう。
guest

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

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

otn

総合スコア84555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KiKiKi_KiKi

2015/08/23 06:46

コピペでコメントしてしまってスミマセンm_ _m こちらのコードも質問の要件が定かで無い部分があるのですが、 menu1のジュースが2本存在することになってしまう場合と言いますか、 各配列から同じ値が複数回出力されてしまう可能性があるように思います。
guest

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

horohoro

総合スコア490

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KiKiKi_KiKi

2015/08/23 06:45

質問の要件が定かで無い部分があるのですが、 menu1のジュースが2本存在することになってしまう場合と言いますか、 各配列から同じ値が複数回出力されてしまう可能性があるように思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問