2009-11-27 74 views
2

我如何從我的linq查詢中選擇一個隨機行?隨機Linq查詢

我想:

Bot bot = (from a in dc.Bot 
      select a).OrderBy(x => Guid.NewGuid()).First(); 

但不工作,我不會有相同的。

回答

4

像這樣的東西可能會奏效:

var random = new Random(); 
var allBots = (from a in dc.Bot select a); 

var randomAmountToSkip = random.NextInt(allBots.Count()); 
var anyBot = allBots.Skip(randomAmountToSkip).First() 
+0

這與鮑勃之前提供的答案不同嗎? – 2009-11-27 15:00:19

+0

我認爲這是西方問題的禁食槍http://meta.stackexchange.com/questions/9731/fastest-gun-in-the-west-problem – Bob 2009-11-27 15:57:33

8

我會用Skip

var query = from a in dc.Bot 
      select a; 

int random = new Random().Next(query.Count); 

Bot bot = query.Skip(random).First(); 
+0

+1。聽起來很合理。 – RichardOD 2009-11-27 14:32:56

+0

+1 - 非常好的主意。將此與Guffa所做的擴展結合起來,這是所有世界中最好的。 – 2010-05-17 10:19:31

+0

@Shaul:由於此方法使用了兩次查詢,因此它不適合作爲擴展。 – Guffa 2010-05-17 11:26:02

2

我爲in my archive擴展方法:

static class IEnumerableExtensions { 

    public static T PickRandomOne<T>(this IEnumerable<T> list, Random rnd) { 
     T picked = default(T); 
     int cnt = 0; 
     foreach (T item in list) { 
     if (rnd.Next(++cnt) == 0) { 
      picked = item; 
     } 
     } 
     return picked; 
    } 

}  

用法:

Random rnd = new Random(); 
Bot bot = (from a in dc.Bot select a).PickRandomOne(rnd); 

此方法的優點是您不需要知道事先有多少項目,因此您不必運行查詢兩次。

+0

+1 - 很好的延伸! – 2010-05-17 10:08:08

+0

掛起 - 請解釋一下:您的foreach循環如何保證您將設置「pick」值?並且這種方法不會固有地支持枚舉結束時的項目,從而使它不那麼隨機? – 2010-05-17 13:13:00

+0

@Shaul:'rnd.Next(1)'總是返回0,所以第一項總是放在'可選'變量中。第二個項目有50%的機會取代第一個項目,在整個收集過程中以下降概率等等,所以算法沒有偏差。 – Guffa 2010-05-17 15:51:31