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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

4回答

5023閲覧

javanによる開発 重みのある配列をシャッフルして選択する

s36a

総合スコア8

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2015/09/03 15:17

編集2015/09/05 06:54

javaに関する質問なんですが,配列をシャッフルして選択された際に.
選択されたものに重みを付けて,2回目シャッフルする際に,
その重みを考慮した選択にするにはどのようにしたらよいでしょうか?

ちょっとイメージしにくいかもしれませんが,

例えば,1〜100の配列があった際に,シャッフルして10個の配列を選びます.
選択された10個の配列には重みを付けます.
そして,もう1回シャッフルする際に先ほど選択した10個の配列(重みのある)が出やすくするような感じにシャッフルをしたいのですが...

<追記>回答ありがとうございます.ちょっとやってみているのですが,ちょっとうまくいきません.

ArrayList<Integer> list = new ArrayList<Integer>(); for ( int y = 0; y < 100; y++ ) { list.add(y); } Collections.shuffle(list); for(int i=0; i<10; i++) { int x = 0; x = list.get(i); }

<追記2>
import java.util.;
import java.lang.
;
import java.io.*;

public class Test1{
public static void main(String []args){

ArrayList<Integer>random = new ArrayList<Integer>(); ArrayList<Integer> copy = new ArrayList<Integer>(); for (int y = 0; y < 100; y++ ) { random.add(y); } System.out.println("1回目シャッフルした場合"); Collections.shuffle(random); System.out.println(random); for(int f=0; f<10; f++) { int x_list = random.get(f); copy.add(x_list); random.add(x_list); } System.out.println("1回目に採用する10個の数字は"); System.out.println(copy); System.out.println("2回目行うときにランダムリストに1回目の数字を追加"); System.out.println(random); } }

ここまでは書けました.やはり再度シャッフル際にリストから弾く場合はremoveを使うのでしょうか?

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

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

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

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

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

swordone

2015/09/03 15:18

すみません,具体例を挙げて説明していただけますか?
s36a

2015/09/04 15:23

みなさんありがとうございます. 頑張ってやってみます!
guest

回答4

0

要素と重みをひも付けて管理するべきだと思います.そのためのクラスを用意します.
下記のコードは汎用的にするためにジェネリクスを使っていますが型固定でも構いません.

java

1public class ElementWithWeight<T>{ 2 private T element; //要素 3 private int weight; //重み 4 5 public ElementWithWeight<T>(T element){ 6 this.element = element; 7 } 8 9 //...ほか,必要そうなメソッドはいくつかあるが省略 10}

配列をシャッフルし,特定の要素に重み(≠1)をつけたとします.
以下,かなりゴリ押しですが
0. まず,すべての重みの合計を算出する(重みがないものは1)
0. 合計値未満の乱数を発生させる
0. 配列の先頭から順に要素の重みを取り出し,重みの合計を出す
0. 乱数<重みの合計となった時点の要素と先頭を入れ替える
0. 1. の重みの合計から4. で選ばれた要素の重みを引き,2. に戻る.ただし,3. で取り出すのはすでに選んだ個数分先の要素から(2周目であれば2番目,インデックス番号1から)
こうなると思います.


追記
自分でコードを書いてみたら,どうやらジェネリクスを持つ要素の配列は作れないようなので,ジェネリクスを使わず型を固定して使ったほうが良さそうです.

追記2
もっと別の方法では,重みのある要素の数を増やしてしまうという方法が考えられます.
重みを付ける要素が決まったあと,Listにその要素を増えた重み分追加します.
そしてシャッフルしたあと,重複する要素の内最初に出てくるもの以外を取り除く必要があります.

投稿2015/09/03 16:13

編集2015/09/04 13:10
swordone

総合スコア20651

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

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

0

定石としては
重みの累積和を計算し
例)重みw={1,1,2,6}に対して累積重みsw={1,2,4,10}

累積重みの一番最後までの乱数を生成し、
例)0~10

要素を先頭から見て、累積重みが初めて生成した乱数以下になるものを選択します。

0 1 2 4 10 |---|---|-------|-----------------------| < 1>< 1>< 2 >< 6 > * *:生成した乱数 この場合先頭を要素[0]として要素[2]が抽選された。 重みが大きい要素ほど区間が広くなるので、重みを反映した確率で抽選できる。

複数を抜き出す場合は、抽選されたものをリストから抜かずに再び抽選(復元抽出)し、
同じものを引いたらやり直すか、(結果的に非復元抽出)
抽選されたものをリストから抜いて、抜き出すたびに累積重みを計算し直すかです

投稿2015/09/05 15:44

編集2015/09/05 15:48
ozwk

総合スコア13521

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

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

0

実装方法よりも、仕様を詰めたほうがいいと思います。

選択した10個の配列(重みのある)が出やすくする

を如何にシステム化できるように落としこむか?が課題です。

例えば、以下の様な感じは如何でしょうか。

1.100個の要素から10個をランダムに取り出す。
2.10個のうち、何個採用するかランダム(5以上10未満)に決める。
3.10個のうち、上記で取得した採用数をランダムに抽出する。...A
4.抽出されなかった90個のうち、Aで不採用とした数だけランダムで抽出する。...B
5.AとBをマージする。

投稿2015/09/05 01:20

TetsujiMiwa

総合スコア1124

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

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

s36a

2015/09/05 04:13

TetsujiMiwaさんありがとうございます! ちょっとやってみたのですが,あまり10個の配列(重みのある)を選んでくれるような感じにはなりませんでした.やはり,一回採用したらその数だけ増やして,採用されたら抽出するとかにしないといけないかもしれないです...
swordone

2015/09/05 04:24

どういう重みの付け方をしているのですか? 重み付けはあくまで確率の操作で,その数字が確実に選ばれる保証はしませんよ?
TetsujiMiwa

2015/09/05 05:47

s36aさん 重複抽出の対処が必要ですが、 数を増やすというのもいいアイデアですね。 10個の配列をそれぞれ10個ずつ増やせば、効果が見えるかもしれないです。
s36a

2015/09/05 05:52

swordoneさん 例えば,10個選ばれた際にその10個を追加して,二回目選ぶ際の確率を上げるなどです...
s36a

2015/09/05 05:55

TetsujiMiwaさん たたその方法だと重複した場合の対処をどうしようかと... 選択されたさいに選ばれたものを追加していくのはいいんですが,被ったときにどのようにして弾くのが...問題ですよね...
TetsujiMiwa

2015/09/05 06:05

s36aさん その際は、重複個数分だけ再抽選となるでしょうね。
swordone

2015/09/05 06:25

私の回答に書きましたが,重みの分数を増やしてシャッフルして, その後重複分をリストから消せばいいのでは?
s36a

2015/09/05 06:55

swordoneさん removeで消すとかでしょうか?
swordone

2015/09/05 07:05 編集

そうです. 最初の位置はindexOf,最後の位置はlastIndexOfで取得できるので, 前者と後者を比較して違えば後者をremoveする,という方法があるのではないでしょうか. もっとも,最初から重複する要素があった場合には使えませんが・・・
guest

0

方向性が違うようなので、回答は消します

投稿2015/09/04 05:51

編集2015/09/05 14:46
anonymouskawa

総合スコア856

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問