0からnまでを要素として含む同じ3つの配列から、
重複のないように、3つずつ要素を含む配列を作成する関数はどう定義すればいいでしょうか?
function make3Array (n){ let arr = []; // 処理 // return arr; }
のような関数を考えています。
例えば、nが9の場合は、
[0,1,2,3,4,5,6,7,8,9] [0,1,2,3,4,5,6,7,8,9] [0,1,2,3,4,5,6,7,8,9]
を重複のないように並べ替えて、以下のような2次元配列を生成したいです。
[ [0,3,7], [2,0,8], [5,6,2], [7,2,6], [1,8,3], [8,7,1], [9,1,5], [6,9,4], [3,4,9], [4,5,0], ]
ご教授いただけるとありがたいです。
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/10/02 13:18
2019/10/02 13:23
2019/10/02 13:26
回答4件
0
[ [0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7], [6,7,8], [7,8,9], [8,9,0], [9,0,1], ]
こう並べるのが簡単です。必要なパラメーターは n だけで、元の配列のことは考える必要ありません。
[8,9,0]
これは次のように求められます。
[(8+0)%(n+1),(8+1)%(n+1),(8+2)%(n+1)]
追記
JavaScript
1const n = 9; 2const rows = n + 1; 3const columns = 3; 4 5let exclude = [...Array(columns).keys()].map(column => []); 6 7const dest = [...Array(rows).keys()].map(row => { 8 let result = []; 9 for (let i = 0; i < columns; i++) { 10 let array = [...Array(rows).keys()]. 11 filter(a => exclude[i].findIndex(b => a === b) < 0). 12 filter(a => result.findIndex(b => a === b) < 0); 13 const r = Math.floor(Math.random() * array.length); 14 result.push(array[r]); 15 exclude[i].push(array[r]); 16 } 17 return result; 18}); 19 20console.log(dest);
投稿2019/10/02 13:17
編集2019/10/02 14:40総合スコア28669
0
冗長だし、がっさいですが、
(しかも書き方も古い)
下記でいかがでしょうか。
発想を変え、三つの配列を、
いったん一つの配列にまとめ、
そこから、一個一個にランダムにとってきた数値を入れていくやり方です。
正直、同じ発想でも、もっとスマートな方法があるかと。
(while使いまくってるのもけっこう危険)
javascript
1function make3Array (n, column) { 2 const arr = [], 3 baseArr = []; 4 5 // ベースとなる、n * columnの配列を作成 6 for (let ci = 0; ci < column; ci++) { 7 const insertOneArr = []; 8 for (let ni = 0; ni < n + 1; ni++) { 9 insertOneArr.push(ni); 10 } 11 baseArr.push(insertOneArr); 12 } 13 14 // ベースを一つにまとめた配列を用意 15 const allSerial = []; 16 baseArr.forEach(val => { 17 val.forEach(vi => { 18 allSerial.push(vi); 19 }); 20 }); 21 22 // まとめた配列がなくなるまで繰り返す 23 while (allSerial.length > 0) { 24 let insertArr = []; 25 // columnの数だけ、入るよう繰り返す 26 while (insertArr.length <= column && allSerial.length > 0) { 27 // まとめた配列のランダムのインデックスを用意 28 let rn = Math.floor( Math.random() * allSerial.length ); 29 // 一つの配列にその数値が含まれる限り、ランダムインデックスを入れなおす 30 while ( insertArr.includes(allSerial[rn]) ) { 31 rn = Math.floor( Math.random() * allSerial.length ); 32 } 33 // 値渡しにするために、変数に格納 34 const ti = allSerial[rn]; 35 // 一つの配列に格納 36 insertArr.push(ti); 37 // まとめ配列の数値要素を削除 38 allSerial.splice(rn, 1); 39 // 一つの配列が、columnの数になったら、最終的に返したい配列にプッシュ 40 if (insertArr.length == column) { 41 // 値渡しにするため、concatメソッドを使用 42 arr.push(insertArr.concat()); 43 // まとめ配列が残っている限り、一つ要素用配列をクリア 44 if (allSerial.length > 0) { 45 insertArr = []; 46 } 47 } 48 } 49 } 50 51 return arr; 52} 53 54console.log(make3Array(9, 3));
投稿2019/10/02 16:37
総合スコア9555
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
こんにちは
ご質問にある
0からnまでを要素として含む同じ3つの配列から、
という趣旨に沿って、これら3つの配列 ar1
, ar2
, ar3
を作成するステップを以下のように考えました。
(1) 与えられた n
によって、 0 から n までを要素とする配列 ar1
を作成する。
例えば、 n が 9 のとき、 ar1
は、 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(2) 上記 (1) で得られた ar1
をランダムに並び替え、かつ、以下の条件
- 0 以上 n 以下の任意の整数 i に対して、
ar1[i] ≠ ar2[i]
を満たす配列 ar2
を作成する。
例えば、 n が 9 のとき、 ar2
として、 [6, 8, 4, 9, 5, 1, 7, 3, 0, 2]
を作成
(3) 上記 (1) で得られた ar1
をランダムに並び替え、かつ、以下の条件
- 0 以上 n 以下の任意の整数 i に対して、
ar1[i] ≠ ar3[i]
かつar2[i] ≠ ar3[i]
を満たす配列 ar3
を作成する。
例えば、 n が 9 のとき、 ar2
として、 [2, 6, 5, 4, 0, 8, 1, 9, 7, 3]
を作成
(4) 上記 (1)(2)(3) で得られた ar1
, ar2
, ar3
の同じ位置の要素を集めた配列を要素とした配列を作成
上記の例だと、以下が得られます。
[[0, 6, 2], [1, 8, 6], [2, 4, 5], [3, 9, 4], [4, 5, 0], [5, 1, 8], [6, 7, 1], [7, 3, 9], [8, 0, 7], [9, 2, 3]]
以下は上記の各ステップをコードにしたものです。
javascript
1function sample(ary) { 2 return ary[Math.floor(Math.random() * ary.length)]; 3} 4 5function make3Array (n) { 6 7 // 0 から n までを要素として含む配列 ar1 を作成 8 const ar1 = [...Array(n+1)].map((_, i) => i) 9 10 // ar1 と同じ位置に同じ要素を持たない配列 ar2 を作成 11 let ar2 12 while(true) { 13 ar2 = [] 14 ar1.forEach((_, i) => { 15 const candidates = ar1.filter(e => e !== ar1[i] && !ar2.includes(e)) 16 ar2.push(sample(candidates)) 17 }) 18 if (typeof ar2[n] !== 'undefined') 19 break 20 } 21 22 // ar1, ar2 と同じ位置に同じ要素を持たない配列 ar3 を作成 23 let ar3 24 while(true) { 25 ar3 = [] 26 ar1.forEach((_, i) => { 27 const candidates = ar1.filter(e => e !== ar1[i] && e !== ar2[i] && !ar3.includes(e)) 28 ar3.push(sample(candidates)) 29 }) 30 if (typeof ar3[n] !== 'undefined') 31 break 32 } 33 34 // ar1, ar2, ar3 の同じ位置の要素を集めた配列を要素とした配列に変換 35 return ar1.map((_, i) => [ar1[i], ar2[i], ar3[i]]) 36} 37
- **動作確認用CodePen: ** https://codepen.io/jun68ykt/pen/oNvKQKd?editors=0012
以上、参考になれば幸いです。
追記
以下、別解です。
3つの配列
を、 ar1
, ar2
, ar3
として作ることは先の回答と変わりありませんが、配列をシャッフルするために lodash の _.shuffle を使い、配列を回転(rotate)させる関数を、stackoverflow のこの回答から拝借します。
javascript
1function arrayRotate(arr, reverse) { 2 if (reverse) arr.unshift(arr.pop()); 3 else arr.push(arr.shift()); 4 return arr; 5} 6 7function make3Array (n) { 8 9 // 0 から n までをランダムな順番で含む配列を作成する。 10 const ar1 = _.shuffle([...Array(n+1)].map((_, i) => i)) 11 12 // ar1 をローテートした配列を得る 13 const ar2 = arrayRotate([...ar1]) 14 15 // ar2 をローテートした配列を得る 16 const ar3 = arrayRotate([...ar2]) 17 18 // ar1, ar2, ar3 の同じ位置の要素を集めた配列を要素とした配列を得る 19 const ar = ar1.map((_, i) => [ar1[i], ar2[i], ar3[i]]) 20 21 // 上記で得られた配列をシャッフルした配列を返す 22 return _.shuffle(ar) 23}
- **動作確認用CodePen: ** https://codepen.io/jun68ykt/pen/pozMLXy?editors=0012
投稿2019/10/02 14:33
編集2019/10/02 18:51総合スコア9058
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2019/10/02 14:53
2019/10/02 15:06
2019/10/02 15:22
2019/10/02 15:33
2019/10/02 15:44
2019/10/02 16:27
2019/10/02 18:39 編集
0
配列をシャッフルするアルゴリズムはフィッシャー–イェーツのシャッフル - Wikipediaが有名ですね。
JSでの実装例は下記。
JavaScript アルゴリズムで配列をシャッフルする - Qiita
一つ目の[0,1,2,3,4,5,6,7,8,9]の配列を上記の方法でシャッフルする。
二つ目の[0,1,2,3,4,5,6,7,8,9]の配列をシャッフルして、一つ目と比較して重複があったら再トライ、重複がないのが出現するまで繰り返す。
三つ目の配列もシャッフルして、一つ目、二つ目と比較して重複がなくなるまで繰り返す。
というアルゴリズムはどうでしょう。
無駄が多いのでもっとスマートなアルゴリズムかあるとは思います。
投稿2019/10/02 13:46
編集2019/10/02 13:48総合スコア34073
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。