確率に基づいてランダムな文字を生成するのに問題があります。
たとえば、文字J、K、Q、Y、Zは、それぞれ1/96の確率で発生します。同様のプロセス(より高い確率で)が他の文字にも使用されます。
誰かがこれを行う方法を教えてもらえますか?
具体的に編集する:確率の分数に基づいてランダムな文字の文字を返す「getRandomLetter」というメソッドを作成しています。
確率に基づいてランダムな文字を生成するのに問題があります。
たとえば、文字J、K、Q、Y、Zは、それぞれ1/96の確率で発生します。同様のプロセス(より高い確率で)が他の文字にも使用されます。
誰かがこれを行う方法を教えてもらえますか?
具体的に編集する:確率の分数に基づいてランダムな文字の文字を返す「getRandomLetter」というメソッドを作成しています。
特定の確率を持つ要素の離散セットから選択する一般的な方法は、ランダムな浮動小数点数を選択し、それがどの範囲にあるかを調べることです。例を挙げて説明します。確率がそれぞれ 0.255、0.407、0.338 の 3 つの文字 A、B、C から選択するとします。0 から 1 の間の乱数を計算します。
double r = Math.random();
まず、0 から 0.255 の範囲と比較します。
if (r < 0.255) {
return 'A';
}
次に、0.255 から (0.255 + 0.407) の範囲に:
else if (r < 0.662) {
return 'B';
}
どちらでもない場合は、次のようにする必要があります'C'
。
else {
return 'C';
}
if
アルファベットの 26 文字すべてでこれを行う場合、 -else
ステートメントの 26 ケースすべてを書き出すのは面倒です。事前にできることは、文字の配列とそれぞれの確率を準備することです。
char[] chars = {'A', 'B', 'C', ...};
double[] probabilities = {0.01, 0.02, 0.05, ...};
そして、次if
のようなループを使用して、そのすべてを自動化できます。
double r = Math.random();
double cdf = 0.0;
for (int i = 0; i < chars.length; i++) {
cdf += probabilities[i]
if (r < cdf) {
return chars[i];
}
}
return chars[chars.length - 1];
あなたの場合、すべての確率が 1/96 の倍数である場合、浮動小数点数の代わりに 96 未満のランダムな整数を選択して同じことを行うことができます。int
s の代わりにdouble
s を使用し、 の代わりに を使用rnd.nextInt(96)
して 0 から 95 までの整数を選択しますMath.random()
。また、probabilities
配列には実際の確率の 96 倍が含まれます。
char[] chars = {'A', 'B', 'C', ...};
int[] probabilities = {5, 2, 4, ...}; // needs to sum to 96
// later...
int r = rnd.nextInt(96);
int cdf = 0;
for (int i = 0; i < chars.length; i++) {
cdf += probabilities[i]
if (r < cdf) {
return chars[i];
}
}
return chars[chars.length - 1];
ここで、バッグからスクラブル タイルを引き出すようなことをしている場合、それは置き換えのないサンプリング プロセスであるため、よりトリッキーになります。つまり、ドローするたびに確率が変化します。その場合のより良い方法は、実際にコレクションを使用してバッグをシミュレートし、その文字があるタイルごとに文字のコピーを 1 つ追加することだと思います。chars
同じ配列とprobabilities
前の配列を使用して、ループでこれを行うことができます。
char[] chars = {'A', 'B', 'C', ...};
int[] probabilities = {5, 2, 4, ...}; // number of tiles with each letter
LinkedList<Character> bag = new LinkedList<Character>();
for (int i = 0; i < chars.length; i++) {
for (int n = 0; n < probabilities[i]; n++) {
bag.add(chars[i]);
}
}
次にbag.shuffle()
、タイルをランダム化し、bag.pop()
ランダムに 1 つ選択できるようにします。
Java での乱数の生成に関するドキュメントを次に示します。
ここで、0 から 95 までのランダムな整数 (96 の可能なバリアント) を生成するとします。
次に、各文字をそれらの数字の 1 つにマップできます。それを行う簡単で汚い方法は、switchステートメントです
switch (randomNumber)
{
case 0:
//decide that you want J
break;
case 1:
case 2:
// maybe you want a letter to have a 2/96 probability
break;
}
それを行う別の簡単な方法は、文字の配列を使用することです。
Random rand = new Random(new Date().getTime())
char[] charArray = {'A','B','C','C','D','E','F','F','F'};
char chosenChar = charArray[rand.nextInt(0, 96)];
Random r = new Random();
char c = (char) r.nextInt(25)+65;
あなたができることは次のようなものです:
List<char> letters = new List<char>();
Dictionary<int,List<char>> set1 = new Dictionary<int,List<char>>();
set1.Key = 2;
set1.Value = new List<char>{'A','B'} //blah blah blah
これらの辞書の配列またはリストを作成し、それらを foreach します
foreach (char theChar in set1.Value)
{
for (int i = 0; i < set1.Key;i++)
{
letters.add(theChar);
}
それから、
Random random = new Random();
char nextchar = letters[random.nextInt(letters.Count - 1)];
選ばれる可能性が高いほど、リストに追加する回数が多くなります。
また、必要に応じて、文字を 1 つの長さの文字列に置き換えることができます。
編集:文字に追加する古い方法は次のとおりです。
for (int i = 0; i < 4; i++) // 4 times
{
letters.add('a');
}
for (int i = 0; i < 3; i++) // 4 times
{
letters.add('b');
}
等
最も楽な解決策は、特定の文字の出現確率に対してコンパクトなコンテナーを必要とすることです。確率関数 (離散分布関数) として機能する HashMap を使用することをお勧めします。このような:
HashMap<Character, Double> map = new HashMap<Character, Double>();
for(Character c : {'J', 'K', 'Q', 'Y', 'Z'}) {
map.put(c, 1.0 / 96.0);
}
// and so on
念のため、すべての確率の合計が に等しいことを確認するとよいでしょう1.0
が、数値は確率の重みとして扱われ、最後に正規化されます。わかりますよね?
純粋に数学的アプローチでは、累積分布関数を作成し、それを元に戻してから、その関数の使用を明示する必要があります。そうすれば、ほぼすべての確率分布で任意のランダム値を生成するソリューションを提供できます。
すぐにやってみましょう:
double sum = 0.0, partialSum = 0.0;
HashMap<Double, Character> dist = new HashMap<Double, Character>();
for(Entry<Character, Double> entry : map.entrySet()) {
sum += entry.getValue(); // for normalization purpose, if you are really sure
// that all the probabilities sum up to 1.0, then the first loop is redundant
}
for(Map.Entry<Character, Double> entry : map.entrySet()) {
dist.put(partialSum / sum, entry.getKey());
partialSum += entry.getValue(); // the cumulative probability here
}
マップを使用するには、電話するだけです
Random r = new Random();
...
dist.get(r.nextDouble());