IEnumerable.ElementAt - Argument Out Of Range Exception when Value Exists

Viewed 885

I have this piece of code that gets a random number from the count of a list (-1) and then gets the element at that index. I then remove the object from that list and the code is called until all objects are gone from that list.

I'm a bit confused as to how there can be 13 indexes (0-12) and the integer I'm using to get the element at is 11. How can this be out of range of the valid values?

private Player GetRandomPlayer(List<Player> entries)
{
            var rIdx = rnd.Next(entries.Count - 1);
            var player = entries.Where(i => i.Seed == null).ElementAt(rIdx);
            entries.Remove(player);

            return player;            
}

Images of exceptions and test case:

List with 13 values: https://ibb.co/wQdq1q4

Exception including int used to get a value:https://ibb.co/mJXwMFh

2 Answers

The ElementAt() method works on the return value of your Where clause. If there are less than rIdx+1 elements having Seed == null you get the exception.

By assuming what you want to achieve, I think this should work:

// filter list
var nullEntries = entries.Where(i => i.Seed == null).ToList();

// use only filtered values
var rIdx = rnd.Next(nullEntries.Count - 1);
var player = nullEntries[rIdx];
entries.Remove(player);

The choice of rIdx counts everyone; but not everyone will match the predicate i => i.Seed == null. So if there are 13 players, 3 unseeded, and you choose player 5... boom.

Fix: apply the predicate before the count.

Related