2009-11-27 69 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