Tom Gullen
Tom Gullen

Reputation: 61773

Linq method to return a random set of records

I have this function:

/// <summary>
/// Returns an array of random articles, ID and titles only
/// </summary>
/// <param name="SectionID">Section ID to return</param>
/// <param name="Count">Number of articles to return</param>
/// <returns></returns>
public ArticleOverview[] RandomArticles(int SectionID, int Count)
{
    ArticleOverview[] ReturnLinks;

    // Pick a random tutorial and redirect to it
    using (MainContext db = new MainContext())
    {
        // Select rows
        var q = (from c in db.tblArticles where c.IsDeleted == false && c.SectionID == SectionID select new { c.ID, c.Title });
        int count = q.Count();
        int index = new Random().Next(count);
        var Articles = q.Skip(index).Take(Count);

        // Size array
        ReturnLinks = new ArticleOverview[Articles.Count()];

        int InsertIx = 0;
        foreach (var Rec in Articles)
        {
            ReturnLinks[InsertIx] = new ArticleOverview(Rec.ID, Rec.Title, SectionID);
            InsertIx++;
        }
    }

    return ReturnLinks;
}

There are two problems with this method:

Thanks for any help! I'm using SQL Server Express 2008 R2.

Upvotes: 1

Views: 3041

Answers (4)

Mo Valipour
Mo Valipour

Reputation: 13496

1 . Define Random class instance to have it "More random"

2 . Use the following code to select random elements

var result = Enumerable.Range(0, count).OrderBy(a => Rand.Next()).Take(resCount).Select(i => q[i]);

Upvotes: 0

Mark Wilkins
Mark Wilkins

Reputation: 41262

Another potential issue is that the current method does not select each record with the same probability. A simple way to see that is suppose that 9 of 10 records are desired. The current method would have only a 10% chance of selecting the first record yet it would always select the 10th record.

It seems it would be better to generate a random set of record numbers (such as described in this post). Then use those to choose those entries from the result set.

Upvotes: 0

faester
faester

Reputation: 15086

How random do you need the results to be?

Well you could select new anonymous random values from 'q' and afterwards order by that random number and select top count. The obvious drawback is that all articles would need to be read into memory instead of delegating the selection to db.

Upvotes: 0

DaveShaw
DaveShaw

Reputation: 52818

Just use the method in Random row from Linq to Sql to do an orderby ctx.Random() and do a .Take(sampleSize) on the results instead of FirstOrDefault

Upvotes: 5

Related Questions