Reputation: 28137
Is there any way to access the IEnumerable<T>
collection being build up by yield return
in a loop from within the method building the IEnumerable
itself?
Silly example:
Random random = new Random();
IEnumerable<int> UniqueRandomIntegers(int n, int max)
{
while ([RETURN_VALUE].Count() < n)
{
int value = random.Next(max);
if (![RETURN_VALUE].Contains(value))
yield return value;
}
}
Upvotes: 0
Views: 603
Reputation: 1502646
There is no collection being built up. The sequence that is returned is evaluated lazily, and unless the caller explicitly copies the data to another collection, it will be gone as soon as it's been fetched.
If you want to ensure uniqueness, you'll need to do that yourself. For example:
IEnumerable<int> UniqueRandomIntegers(int n, int max)
{
HashSet<int> returned = new HashSet<int>();
for (int i = 0; i < n; i++)
{
int candidate;
do
{
candidate = random.Next(max);
} while (returned.Contains(candidate));
yield return candidate;
returned.Add(candidate);
}
}
Another alternative for unique random integers is to build a collection of max
items and shuffle it, which can still be done just-in-time. This is more efficient in the case where max
and n
are similar (as you don't need to loop round until you're lucky enough to get a new item) but inefficient in the case where max
is very large and n
isn't.
EDIT: As noted in comments, you can shorten this slightly by changing the body of the for
loop to:
int candidate;
do
{
candidate = random.Next(max);
} while (!returned.Add(candidate))
yield return candidate;
That uses the fact that Add
will return false
if the item already exists in the set.
Upvotes: 5