简体   繁体   中英

How to Generate one random number more than other random numbers in an array?

I have a list of numbers, for example: {1,2,3,4,5,6} .

I want to generate these numbers randomly, which I did this like this:

void Update(){
    float ran = Random.Range(1,6);
    print(ran);
}

How do I generate or print 3 more than other numbers?

If you want skewed distribution you can, say, map values generated to a desired distribution

// all 1..6 are equal with exception of 3 which appears more frequently 
// 1..2, 4..6 - 10% each (1 occurence  per 10 items)
// 3          - 50%      (5 occurences per 10 items)
private static int[] map = new int[1, 2, 3, 4, 5, 6, 3, 3, 3, 3];

...

void Update{
  float ran = map[Random.Range(map.Length)];
  print(ran);
}

Here is some kind of soluton, using probability theory, but it's overenginered. It also can have minor syntax mistakes, becouse I am far from visual studio now(

var data = new float[] {1, 2, 3, 4, 5, 6};
var indexToWeight = (index) => {
  if (index == 3) return 2;
  return 1; 
};
var total = data.Select((value, index) => indexToWeight(index)).Sum(); 
var weightedData = data.Select((value, index) => Tuple.Create(value, indexToWeight(index)/(float)sum)).ToList();
var boundedData = new List<Tuple<float, float>>(weightedData.Count);
float bound = 0.0f;
for (int i = 0; i < weightedData.Count; i++) {
  boundedData.Add(Tuple.Create(weightedData[i].Item1, bound));
  bound += weightedData[i].Item2;
}

var weightedToValue = (List<Tuple<float, float>> wv, float p) => {
  var pair = wv.FirstOrDefault(item => item.Item2 > p);
  if (pair != null) return pair.Item1;
  return vw.Last().Item1; 
}; 
Random random;
var randomizedData = Enumerable.Range(1, data.Count).Select(index => weightedtoValue(weightedData, random.NextDouble())).ToArray();   

Set threeMultiplier to 1 for a normal distribution, 2 for two times more 3's, 3 for three times more 3's, and so on.

void Update() {
    int threeMultiplier = 2; // Twice as much 3's
    int maxNumber = 6;
    int num = Random.Range(1, threeMultiplier * maxNumber);
    if (num > maxNumber) num = 3;
    print(num); 
}

One solution for "rolling dice hack" could be this: float ran = Random.Range(1,10);

"convert ran to int"

switch (ran) 
 case 1: 
   return 1
 case 2: 
   return 2
 case 3:
   return 3
 case 4:
   return 4
 case 5: 
   return 5
 case 6:
   return 6
 default:
   return 3

so you will have 50% chances for 3, and 10% for each other, to decrease the number of 3-s change 10 to a smaller value ^^

Check this example i made in .Net fiddle. In this code you have 2 possibilities. Im pretty sure this resolves your problem, and its a pretty simple solution. Of course in Unity you might want to use Random.Range... change the names of some vars yada yada.

1- You can print as many times as there are elements on your list, so a list with 'n' elements will always print 'n' numbers as output.

2- You can print any ammount you want, as long as you change the variable timesToPrint

The code will print the goldenNumber based on the chanceToPrintGoldenNumber , else it prints a random element on the list (which can be the golden number by accident).

Example Link HERE!

Code:

public static void Main()
{
    Random rnd = new Random();
    var li = new List<int> {1,2,5,3,6,8};
    var timesToPrint = 10;

    var goldenNumber = 3;

     // this is actually 55% chance, because we generate a number form 0 to 100 and if it is  > than 45 we print it... so 55% chance
    var chanceToPrintGoldenNumber = 45;


    // Print as many times as there are numbers on the list

    Console.WriteLine("Printing as many times as there are elements on the list");

    foreach(var number in li)
    {       
        var goldenNumberChance = rnd.Next(0,100);

        if (goldenNumberChance > chanceToPrintGoldenNumber) // 55% chance to print goldenNumber
        {
            Console.WriteLine(goldenNumber);            
        }
        else
        {           
            var i = rnd.Next(0,li.Count);
            Console.WriteLine(li[i]);           
        }
    }

    Console.WriteLine("****************** END ***************************");

    // Print as many times as the value of your "timesToPrint".

    Console.WriteLine("Printing as many times as the value on timesToPrint ");

    for(var i=0; i< timesToPrint; i++)
    {
        var goldenNumberChance = rnd.Next(0,100);

        if (goldenNumberChance > chanceToPrintGoldenNumber) // 55% chance to print goldenNumber
        {
            Console.WriteLine(goldenNumber);            
        }
        else
        {           
            var n = rnd.Next(0,li.Count);
            Console.WriteLine(li[n]);           
        }

    }

}

I'd do something like this for weighted distribution:

public class RandomGenerator
{
    Dictionary<Tuple<double, double>, Tuple<int, int>> probability;
    Random random;

    public RandomGenerator(Dictionary<double, Tuple<int, int>> weights)
    {
        random = new Random();

        Dictionary<double, Tuple<int, int>> percent = weights.Select(x => new { Key = x.Key / weights.Keys.Sum(), Value = x.Value }).ToDictionary(t => t.Key, t => t.Value);
        probability = new Dictionary<Tuple<double, double>, Tuple<int, int>>();
        double last = 0;
        foreach (var item in percent.OrderBy(x => x.Key).Select(x => new { Key = x.Key, Value = x.Value }))
        {
            probability.Add(new Tuple<double, double>(last, last + item.Key), item.Value);
            last += item.Key;
        }
    }

    public double GetRandomNumber()
    {
        double w = random.NextDouble();

        var range = probability.Where(x => w >= x.Key.Item1 && w <= x.Key.Item2).First().Value;

        return random.Next(range.Item1, range.Item2);
    }
}

And you could use it like this:

Dictionary<double, Tuple<int, int>> weights = new Dictionary<double, Tuple<int, int>>();
weights.Add(80, new Tuple<int, int>(1, 100));
weights.Add(20, new Tuple<int, int>(3,3));

var randgen = new RandomGenerator(weights);
var number = randgen.GetRandomNumber();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM