2

I'm trying to come up a LINQ SELECT statement in C# to select random items from specific object instead of ordered items. how do i translate below syntax to random select

random = _dbase.OrderBy(x => x.company).Take(1000);
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Veck
  • 125
  • 1
  • 3
  • 13
  • 2
    If enumeration is short, you can *materialize* it into a *collection* (array, list) and then use `random.Next(0, array.Length)` to obtain random item index; if enumeration is long, please, have a look at *reservoir sampling* https://en.wikipedia.org/wiki/Reservoir_sampling – Dmitry Bychenko Aug 08 '22 at 07:05
  • 1
    If `_dbase` is an `IEnumerable` returned by LINQ-to-SQL, you could use something like [this](https://stackoverflow.com/questions/648196/random-row-from-linq-to-sql). If it's a local collection such as a List or an Array, you could use something like [this](https://stackoverflow.com/questions/3173718/how-to-get-a-random-object-using-linq) instead. – ProgrammingLlama Aug 08 '22 at 07:06
  • 1
    Provide a stored-procedure in your database that returns n-random items. That is the most efficient approach. There you could use for example `TABLESAMPLE`(in case of MS-SQL). See: https://dba.stackexchange.com/q/955/609 – Tim Schmelter Aug 08 '22 at 07:11
  • @DiplomacyNotWar _ dbase is a dbcontext and returns the result to ienumerable random – Veck Aug 08 '22 at 07:16
  • Some examples about how to implement reservoir sampling as mentioned by Dmitry: https://stackoverflow.com/questions/70693494/random-sample-from-an-ienumerable-generated-by-yielding-elements https://stackoverflow.com/questions/48087/select-n-random-elements-from-a-listt-in-c-sharp/48089#48089 – Matthew Watson Aug 08 '22 at 07:55

1 Answers1

2

You cannot select a random item from an IEnumerable because it's a generator that yields values. It has no size so you might be dealing with an infinite IEnumerable which makes the selection of a random item impossible.

A work around would be to create a List<T> (which has a size) from your initial collection and then select a random item.

IEnumerable<object> myCollection = ...;

var myList = myCollection.ToList();

var rng = new Random();
var randomIndex = rng.Next(0, myList.Count);
var randomItem = myList[randomIndex];

But in your case, you would prefer not to fetch all data of your table. Instead you could make the calculation inside the sql request.

Here's a link showing how to do it.

Sneak peek in case it becomes invalid

// DO NOT USE THIS FOR MORE THEN 100 ROWS
var randomRecord = foos.OrderBy( x=> SqlFunctions.Rand() ).FirstOrDefault();

// USE THIS FOR MORE THEN 100 ROWS
var random = Math.Random(foos.Count());

var randomRecord = foos.OrderBy( x=> x.id ).Skip( random ).FirstOrDefault();
Hervé
  • 760
  • 4
  • 9