What is the most efficient way to spawn objects with probability weights in this scenario?

In my game, I currently have a list of gameobjects containing fruits. These fruits currently spawn randomly, but with no probability weights attaches, so any fruit can be spawned at any time using C#.

But I want certain fruits to spawn more than others with a fixed probability. For example, I have oranges, apples, bananas, strawberries and pomegranates, where I want these fruits to spawn with these weights:
Oranges: 40%, Apples: 30%, Bananas: 10%, Pomegranates: 15%, Strawberries: 5%. So oranges will be spawned 40% of time, apples will be spawned 30% of time, with strawberries and pomegranates being spawned rarely.

I’ve heard of using cumulative frequency, but I don’t know how to implement that, nor do I know if its efficient in the long term, since I want to add more fruits later on and give them a fixed probability to spawn at as well.

Thanks

I usually use Weighted Random for stuff like this. With weighted random, 100% is total of all chances combined, so you dont have to care about making the fruit add up to 100%.

In weighted random, you:

  1. Add up all the weights to a sum

    float sum = 0;
    for(var fruit in fruits)
    {
    sum += fruit.spawnRate;
    }

  2. Generate a random number between 0 and sum(exclusive)

    float randomWeight = 0;
    do
    {
    //No weight on any number?
    if(sum == 0)
    return null;
    randomWeight = Random.Range(0, sum);
    }
    while(randomWeight == sum)

  3. Go through all items and check if the random number is less than the weight of that item. If it is not, then subtract that weight.

    for(var fruit in fruits)
    {
    if(randomWeight < fruit.spawnRate)
    return fruit;
    randomWeight -= fruit.spawnRate;
    }
    Your code should never go this far

    return null;

You can easily do what you want with 2 parallel arrays. Let’s say you have an array of probabilities for each fruit like the ones you mentioned. You also have an array of gameobjects that correspond to the probabilities index by index. You can then create a cumulative array at runtime to do your business:

GameObject[] fruit;
float[] probability;	//40% could be 0.4f

float[] cumulative;

void MakeCumulative()	//this function creates the cumulative array
{
	float current = 0;
	int itemCount = probability.Length;
	
	for(int i = 0; i <= itemCount; i++)
	{
		current += probability*;*

_ cumulative = current;_
* }*

* if (current > 1.0f)*
* {*
* Debug.Log(“Probabilities exceed 100%”);*
* }*

}

GameObject GetRandomFruit()
{
* float rnd = Random.Range(0, 1.0f);*
* int itemCount = cumulative.Length;*

* for(int i = 0; i <= itemCount; i++)*
* {*
_ if (rnd <= cumulative*)
{
return fruit;
}
}*_

* return null;*
}