如何使用 Linq 获取随机对象,跳过第一个对象

问题描述 投票:0回答:8

我尝试使用 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++;
}

这是最好的方法吗?

c# .net linq random
8个回答
54
投票

关于:

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

进一步阅读:

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

整个输入中的随机元素

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

r.Next
:

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

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

public static T Random<T>(this IEnumerable<T> 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<T> ?? enumerable.ToList(); 
    return list.Count == 0 ? default(T) : list[r.Next(0, list.Count)];
}

16
投票

另一种古怪的方法(对于较大的数据集来说不是最有效的):

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

11
投票

使用 Fisher-Yates-Durstenfeld 洗牌

(您可以使用辅助/扩展方法来随机播放您的

IEnumerable<T>
序列。或者,如果您使用
IList<T>
,您可以执行就地随机播放,如果您愿意的话。)


4
投票

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

 public static class EnumerableExtensions
    {
        public static T Random<T>(this IEnumerable<T> enumerable)
        {
            var r = new Random();
            var list = enumerable as IList<T> ?? enumerable.ToList();
            return list.ElementAt(r.Next(0, list.Count()));
        }
    }

4
投票

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

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

它的缺点是它将对所有元素应用随机数,但它很紧凑并且可以轻松修改以获取多个随机元素。


4
投票
var rand = new Random();
var selectedPost = q.Skip(rand.Next(0, q.Count())).Take(1).FirstOrDefault();

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

在 SQL 中,这与查询

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


2
投票

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


0
投票

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

Linq 看起来像这样

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

x.Id!=id 

这仅适用于未将所选产品列入列表的情况。

效果完美

© www.soinside.com 2019 - 2024. All rights reserved.