If the elements can be in memory, put them in memory first
List<Element> elements = dbContext.Select<Element>();
Now you know the number of elements. Create a set of unique indexes.
var random = new Random();
var indexes = new HashSet<int>();
while (indexes.Count < k) {
indexes.Add(random.Next(elements.Count));
}
Now you can read the elements from the list
var randomElements = indexes.Select(i => elements[i]);
I assume that the DB contains unique elements. If this is not the case, you will have to create a HashSet<Elements>
instead or to append .Distinct()
when querying from the DB.
UPDATE
As Patricia Shanahan says, this method will work well if k is small compared to n. If it is not the case, I suggest selecting a set n - k indexes to be excluded
var random = new Random();
var indexes = new HashSet<int>();
IEnumerable<Element> randomElements;
if (k <= elements.Count / 2) {
while (indexes.Count < k) {
indexes.Add(random.Next(elements.Count));
}
randomElements = indexes.Select(i => elements[i]);
} else {
while (indexes.Count < elements.Count - k) {
indexes.Add(random.Next(elements.Count));
}
randomElements = elements
.Select((e,i) => indexes.Contains(i) ? null : elements[i])
.Where(e => e != null);
}