如何使用Linq获取随机对象

我想在linq中获取一个随机对象。 我是这样做的。

//get all the answers var Answers = q.Skip(1).Take(int.MaxValue); //get the random number by the number of answers int intRandomAnswer = r.Next(1, Answers.Count()); int count = 0; //locate the answer foreach(var Answer in Answers) { if (count == intRandomAnswer) { SelectedPost = Answer; break; } count++; } 

这是最好的方法吗?

关于什么:

 SelectedPost = q.ElementAt(r.Next(1, Answers.Count())); 

进一步阅读:

下面的评论对密切相关的问题做出了很好的贡献,我将它们包含在这里,因为正如@Rouby指出的那样,搜索这些答案的人可能会找到这个答案,但在这些情况下这些答案是不正确的。

整个输入的随机元素

要使所有元素成为随机选择中的候选元素,您需要将输入更改为r.Next

 SelectedPost = Answers.ElementAt(r.Next(0, Answers.Count())); 

@Zidad添加了一个有用的扩展方法来获取序列中所有元素的随机元素:

 public static T Random(this IEnumerable enumerable) { if (enumerable == null) { throw new ArgumentNullException(nameof(enumerable)); } // note: creating a Random instance each call may not be correct for you, // consider a thread-safe static instance var r = new Random(); var list = enumerable as IList ?? enumerable.ToList(); return list.Count == 0 ? default(T) : list[r.Next(0, list.Count)]; } 

使用Fisher-Yates-Durstenfeld shuffle 。

(您可以使用辅助/扩展方法来重新排列IEnumerable序列 。或者,如果您使用IList ,则可以执行就地随机播放 ,如果您愿意的话。)

另一种古怪的方法(对大型数据集来说效率最高):

 SelectedPost = q.OrderBy(qu => Guid.NewGuid()).First(); 

基于接受的答案的通用扩展方法(不总是跳过第一个,只枚举一次可枚举):

  public static class EnumerableExtensions { public static T Random(this IEnumerable enumerable) { var r = new Random(); var list = enumerable as IList ?? enumerable.ToList(); return list.ElementAt(r.Next(0, list.Count())); } } 
 var rand = new Random(); var SelectedPost = q.Skip(rand.Next(0,q.Count)).Take(1); 

最理想的情况是,您只想对单个值进行函数查询,因此设置Skip / Take跳转到与您生成的随机数匹配的序列号(以数据集的itemcount为界,因此缺少行问题)基于MAX(pkey)的边界不是问题)然后在序列中的该点处阻止第一个项目。

在SQL中,这与查询SELECT Count(*) FROM q ,然后SELECT * FROM q LIMIT {0}, 1其中{0}rand.Next(0, count) ,这应该非常有效。

迟到了,但这是谷歌的一个高调结果。 一个简洁的版本可能是:

 var rnd = new Random(); var SelectedPost = q.OrderBy(x => rnd.Next()).Take(1); 

它的缺点是它会将随机数应用于所有元素,但是它是紧凑的,并且可以很容易地修改为采用多个随机元素。

我发布了一个答案,因为我没有足够的声誉来发表评论。

我喜欢这个答案:

 SelectedPost = q.ElementAt(r.Next(1, Answers.Count())); 

但是ElementAt是零基础的,肯定从1开始,然后转到Answers.Count(),你最终可能会超出范围,你永远不会得到第一个实体。

岂不

 SelectedPost = q.ElementAt(r.Next(0, Answers.Count() - 1)); 

会更好?

当您从数据库中移动大量数据时,拉出所有答案并循环它们并不是最有效的方法。 如果您使用的是自动递增的整数主键,则应获取主键的Max,然后找到该范围内的随机整数。 然后根据从随机函数派生的主键直接获得单个答案。

我在数据库中有产品表,每次用户输入一个产品详细信息我想在页面下方显示10个类似的产品。并且在每次刷新时该列表必须更改。必须随机出现。

Linq看起来像这样

 var products = DataContextFactory.GetDataContext() .Set() .Where(x =>x.Id!=id) .OrderBy(emp => Guid.NewGuid()) .Take(10).ToList(); x.Id!=id 

这仅适用于未将所选产品列入清单。

它完美无缺