Picking a random item from an array

I’ve got an array of objects. I need to pick a random one from that array and test to see if it has a specific property. If it has that property, discard it and pick a new random one from the remaining objects. Keep doing this until I find one without the property or until all objects have been tested.

The code I’m using right now accomplishes this, but it is painfully slow on mobile platforms. This random selection happens in batches of 4 to 6 selections at once, roughly every 5 to 10 seconds, and my current code causes a very noticeable hiccup. I know that resizable arrays are slow, but I don’t know of a better way to do random, non-repeating selection. Any advice?

public Obstacle[] obstacles; //stores a list of potential obstacles this object can spawn

void SetNextObstacle()
{
	ArrayList obsPool = new ArrayList(obstacles); //clone the list of obstacles into a resizable array
		
	bool found = false;	//true once a usable obstacle has been found
		
	while (obsPool.Count > 0  found == false) //choices remain and none found yet
	{
		Obstacle randObs = (Obstacle) obsPool[Random.Range(0, obsPool.Count)]; //pick a random obstacle from the array
			
		if (randObs.IsActive == false) //if it is not in use
		{
			spawnedObstacle = randObs; //use it.
			found = true; //found a usable obstacle, ends the while
		}
		else
		{
			obsPool.Remove(randObs); //not usable, remove from the array
		}
	}
}

Well, no, ArrayList is slow. List isn’t slow; the only reason to use ArrayList instead of List is if you need different types in the same array, which is rare.

–Eric

Ah, ok. I was unfamiliar with the difference. Thanks.

There is random selection library in this thread. Among other things, it has a function for so-called “sampling without replacement” (ie, picking objects from a list at random but never choosing the same one twice on a given run). You may find the code is more efficient if you remove the unchoosable objects all at once and then choose from the remaining ones rather than throwing away false choices as they come up.

That may depend on how often unchoosable items come up in the list. I’m picking from a pool of about 20 items and only 2 or 3 of them are unchoosable at any given time. The chances of hitting multiple unchoosable objects in a row are pretty slim, so it ends up being fairly infrequent that I have to remove more than one object from the list each time a new object is requested. Looping through all the objects in the list and removing the 2 or 3 unchoosables might not save much if anything in this case, but I do appreciate the library none the less :slight_smile:

You could also just use a simple LINQ query:

Simple string example grabbing a random string with a length greater than 3

string[] names = { "Tom", "Dick", "Harry", "Hector", "Lively", "Emily", "Honduras" };

var filtered = names.Where( n => n.Length >= 3 );
var randomItem = filtered.ElementAtOrDefault( new Random().Next() % filtered.Count() );

This one assumes obsPool is your pool of Obstacles which have an ‘isActive’ property:

var filtered = obsPool.Where( n => n.isActive );
var randomItem = filtered.ElementAtOrDefault( new Random().Next() % filtered.Count() );