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

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

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

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

Q&A

解決済

7回答

703閲覧

ランダムに作られた数字が入った配列内に、重複がないようにしたい

mi_mi

総合スコア19

JavaScript

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

0グッド

0クリップ

投稿2018/10/26 02:08

javascript

1var nums =[];//PCのランダム数字6桁の配列 2 var min =1;//最小値 3 var max = 43;//最大値 4 for ( i = 0; i < 6; i++) 5 { 6 nums.push(Math.floor(Math.random()*(max + 1 - min ))+min );//ランダム1~43 7 }

・やりたい事
ランダムに作られた数字を配列にする事ができたのですが、
重複した数字も入ってしまうことがわかりました。
上記のコードを生かして
ランダムにつくられた数字の配列の中で重複がないようにしたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

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

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

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

guest

回答7

0

1 から 43 までの値が順に入った配列を作り、シャッフルしてから最初の 6 つを取り出すのが良いと思います。

JavaScript アルゴリズムで配列をシャッフルする

投稿2018/10/26 02:16

Zuishin

総合スコア28660

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

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

退会済みユーザー

退会済みユーザー

2018/10/26 02:30

どのくらいシャッフルすればいいかがあるとなおよいかと。
Zuishin

2018/10/26 02:40

紹介した Fisher–Yates 法は一回で大丈夫です。
退会済みユーザー

退会済みユーザー

2018/10/26 02:42

なるほど確かに!お返事ありがとうございます。
guest

0

こんなやり方もできないことはないですね

javascript

1var min=1; 2var max=43; 3var choice=6; 4var nums =new Array(max).fill(null).map(function(x,y){ 5 return [Math.random(),y+min]; 6}).sort(function(x,y){ 7 return x[0]>y[0]?1:-1; 8}).map(function(x){ 9 return x[1]; 10}).filter(function(x,y){ 11 return y<choice; 12}); 13console.log(nums);

投稿2018/10/26 03:47

yambejp

総合スコア114759

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

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

yambejp

2018/10/26 03:56

ちなみにmax=43は43個のデータをつくる処理なので 仮にmin=10だと10~52のデータになります。大丈夫ですよね? 文字通り上限値を43にしたいなら、Array(max-min+1)しないといけません
guest

0

new Set

重複を許さない仕様なら、Set が最適だと思います。

JavaScript

1function sample (min, max, length) { 2 const set = new Set; 3 4 while (set.size < length) { 5 set.add(Math.floor(Math.random() * (max - min + 1)) + min); 6 } 7 8 return Array.from(set); 9} 10 11console.log(sample(1, 43, 20));

演算コストを安くするなら、

JavaScript

1function sample2 (min, max, length) { 2 const set = new Set; 3 let i = 0; 4 5 while (i++ < length) { 6 set.add(Math.floor(Math.random() * (max - min + 1)) + min); 7 } 8 9 while (set.size < length) { 10 set.add(Math.floor(Math.random() * (max - min + 1)) + min); 11 } 12 13 return Array.from(set); 14} 15 16console.log(sample2(2, 20, 10));

Re: mi_mi さん

投稿2018/10/27 02:30

think49

総合スコア18162

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

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

0

ベストアンサー

こんにちは。

二通りのやり方によるコードを回答します。ご質問に、

上記のコードを生かして

とありましたので、まず

  • (1) ご質問に挙げられているコードをなるべく生かす案

を示し、追加でもうひとつ、同じお題を私がスクラッチから書くとしたらこうかな、という

  • (2) Lodash の shuffle を使う案

を以下にて回答します。

(1) ご質問に挙げられているコードをなるべく生かす案

ループ毎に1個ずつ乱数を生成してそれを nums に入れることは同じですが、その数が nums に含まれていない場合にのみ numsに追加します。このような追加の仕方でnumsの長さが 6 になったときにループから抜けます。このような考え方で修正したコードが以下です。(※これは ppn さんのご回答の、要素数を減らしたくない場合 のコードとほぼ同じです。)

javascript

1var nums = []; // ランダム数字6桁の配列 2 3var min = 1; // 最小値 4var max = 43; // 最大値 5 6while (nums.length < 6) { 7 var n = Math.floor(Math.random()*(max + 1 - min )) + min; 8 if (!nums.includes(n)) 9 nums.push(n); 10} 11 12console.log(nums);

しかし、上記だと必ず何回目かまで(あるいは、実用上耐えうる実行時間内)のループで、 nums に 6個の要素が詰め込まれる、とは言えず、無限ループの可能性がゼロではないです。実際は限りなくゼロに近いでしょうけれども、このままにしておくのも何となく心残りですので、乱数の生成回数に適度に上限を設けて、それに達したら numsの要素が6個に満たなくてもループを抜けるようにします。以下そのような上限を追加したコードです。

javascript

1var nums = []; // ランダム数字6桁の配列 2 3var min = 1; // 最小値 4var max = 43; // 最大値 5 6var count = 0; // 乱数を生成した回数 7var MAX_COUNT = 100000; // 乱数生成回数の上限 8 9while (nums.length < 6 && count < MAX_COUNT) { 10 var n = Math.floor(Math.random()*(max + 1 - min )) + min; 11 if (!nums.includes(n)) 12 nums.push(n); 13 count ++; 14} 15 16console.log(nums);

上記のコードの意図は、「1から43までの数から無作為に一個取ることを、最大でも10万回やれば、その中に異なる数字が6個あることは、ほぼほぼ期待していいだろう」ということになります。

(2) Lodash の shuffle を使う案

与えられた配列の要素の順番をランダムに入れ替えることを、シャッフル(shuffle)といいますが、配列の様々な操作が集められているライブラリ Lodash に、 _.shuffle(collection) が用意されていますので、これを使った例を示します。(なお、以下のコードは、Zuishinさんのご回答をコードにしたものの一例にもなっています。)

javascript

1// 1 から 43 までを昇順に含む配列を作成 2const ary1to43 = [...Array(43)].map((_,i) => i+1); 3 4console.log(ary1to43); 5 6// シャッフルした配列を作成 7const shuffled1to43 = _.shuffle(ary1to43); 8 9console.log(shuffled1to43); 10 11// 先頭6個の配列を得る 12const result = shuffled1to43.slice(0,6); 13 14console.log(result);

以下、上記の動作確認用のサンプルです。

なお、Lodash をCDNから利用する場合のURLは以下に記載されています。

 

以上参考になれば幸いです。

投稿2018/10/26 04:08

編集2018/10/27 03:00
jun68ykt

総合スコア9058

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

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

0

https://qiita.com/cocottejs/items/7afe6d5f27ee7c36c61f
を参考に

HTML

1<!DOCTYPE html> 2<html> 3<head> 4 <meta charset="utf-8"> 5</head> 6 7<body> 8 <script> 9 var nums =[];//PCのランダム数字6桁の配列 10 var min =1;//最小値 11 var max = 43;//最大値 12 while(nums.length < 6) 13 { 14 nums.push(Math.floor(Math.random()*(max + 1 - min ))+min );//ランダム1~43 15 // 重複除去 16 nums = nums.filter(function (x, i, self) { 17 return self.indexOf(x) === i; 18 }); 19 } 20 console.log(nums); 21 </script> 22</body> 23</html>

投稿2018/10/26 02:23

rururu3

総合スコア5545

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

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

0

重複を削除したい場合(要素数が減ります)
(※線形リストを走査しないのですこし早いかも?)
(※ランダムな値の範囲がすごく大きいと無駄なコストがあるかも)
(※未検証です)

javascript

1 var nums = [];//PCのランダム数字6桁の配列 2 var min = 1;//最小値 3 var max = 43;//最大値 4 for (i = 0; i < 6; i++) { 5 nums.push(Math.floor(Math.random() * (max + 1 - min)) + min);//ランダム1~43 6 } 7 var dict = {}; 8 nums.forEach(o => dict[o] = 0); // 数値がキーのノードを作成する(distinct) 9 var newNums = Object.keys(nums); 10 console.log(newNums);

要素数を減らしたくない場合

javascript

1 var nums = [];//PCのランダム数字6桁の配列 2 var min = 1;//最小値 3 var max = 43;//最大値 4 while (nums.length < 6) { 5 var newNum = Math.floor(Math.random() * (max + 1 - min)) + min; 6 if (nums.indexOf(newNum) == -1) 7 nums.push(newNum);//ランダム1~43 8 } 9 console.log(nums);

投稿2018/10/26 02:18

編集2018/10/26 02:29
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Zuishin

2018/10/26 02:21

数が減りませんか?
退会済みユーザー

退会済みユーザー

2018/10/26 02:24

減らしたい(distinctしたい)のかなと。減らないのもかいときました。
guest

0

実際のくじ引きとおなじ方法をプログラミングしてみます。
2つの方法を示します。

その1
box に 1... N を順番にいれます。
乱数で rand を得て、box の rand 番目の数字を nums に入れます。box からはその数字は削除します。
これを 6 回 繰り返します。

その2
box に 1... N を順番にいれます。
box の中身をシャッフルします。
先頭の 6 つを nums とします。

nums.js

javascript

1var nums = []; // PCのランダム数字6個の配列 2var min =1; // 最小値 3var max = 10; // 43; // 最大値 4var box = [...Array(max - min + 1).keys()].map(i => i + min) 5// console.log(box); 6 7for (var i = 0; i < 6; i++) { 8 if (box.length == 0) { 9 break; 10 } 11 p = Math.floor(Math.random() * box.length); 12 nums.push(box[p]); 13 box.splice(p, 1); 14} 15console.log(nums); 16 17box = [...Array(max - min + 1).keys()].map(i => i + min) 18for (var i = box.length - 1; i >= 0; i--) { 19 // 0~iのランダムな数値を取得 20 var rand = Math.floor( Math.random() * ( i + 1 ) ); 21 // 配列の数値を入れ替える 22 [box[i], box[rand]] = [box[rand], box[i]] 23} 24nums = box.slice(0, 6); 25console.log(nums);

実行例
イメージ説明

参考情報

  • 連番の数字の配列を作成

https://qiita.com/sakymark/items/710f0b9a632c375fbc31

  • JavaScript アルゴリズムで配列をシャッフルする

https://qiita.com/artistan/items/9eb9a0fb14f4ec3a8764

投稿2018/10/27 10:39

katoy

総合スコア22324

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問