如何从IEnumerable<>中获取随机大小的随机条目列表?在C#中

时间:2013-06-22 08:39:51

标签: c#

我有以下课程:

public class Question
{
    public int    QuestionId { get; set; }
    public string Title { get; set; }
}

并在我拥有的变量中:

IEnumerable<Question> _questions = GetQuestions.Get();

如何收集变量_questions中的问题集合并随机返回集合中1到4个随机问题的列表?

2 个答案:

答案 0 :(得分:6)

您可以先随机播放列表,然后使用Take()

var result = _questions.OrderBy(x => Guid.NewGuid())
                       .Take(new Random().Next(4) + 1);

答案 1 :(得分:2)

您可以使用Reservoir Sampling对未知大小的序列进行单次传递,以选择N个项目的随机集合:

public static List<T> RandomlyChooseItems<T>(IEnumerable<T> items, int n, Random rng)
{
    var result = new List<T>(n);
    int index = 0;

    foreach (var item in items)
    {
        if (index < n)
        {
            result.Add(item);
        }
        else
        {
            int r = rng.Next(0, index + 1);

            if (r < n)
                result[r] = item;
        }

        ++index;
    }

    return result;
}

你这样使用它:

IEnumerable<Question> questions = ...;
Random rng = new Random();
int questionCount = rng.Next(1, 5); // Get between 1 and 4 questions.

List<Question> randomQuestions = RandomlyChooseItems(questions, questionCount, rng);

这通常不比将项目复制到数组并执行Fisher-Yates shuffle更有效,但如果可供选择的列表的大小非常大以及要选择的项目数量,这可能很有用相对较小,因为您只需要存储所选项目而不是原始项目列表。