【问题标题】:How can I get a random sized list of random entries out of an IEnumerable<> in C#如何从 C# 中的 IEnumerable<> 中获取随机大小的随机条目列表
【发布时间】:2013-06-22 08:39:51
【问题描述】:

我有以下课程:

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

在一个变量中我有:

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

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

【问题讨论】:

  • 查看stackoverflow.com/questions/1287567,然后只需将.Take() 与您想要的问题数量一起使用(只需使用Random.Next 即可获得1 到4 之间的随机数)。

标签: c#


【解决方案1】:

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

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

【讨论】:

  • Take 的参数设为 1-4 之间的随机整数,这将是一个完整的答案。
  • @Oded - 对不起 - 我们的 cmets 越界了。我指的是Cuong的回答,而不是你的。你是对的 - 让它成为 1 到 4 之间的随机数,这很好。 :)
  • 在 take 参数中使用随机对象。
  • 请记住,虽然 GUID 是唯一的,但不一定保证是随机的:stackoverflow.com/questions/467271/…
  • 另外,使用适当的随机播放。当你可以拥有 O(n) 时,O(n log n) 有什么意义?
【解决方案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 更有效,但如果要选择的列表的大小非常大并且要选择的项目数量相对较少,这可能会很有用小,因为您只需要存储所选项目而不是原始项目列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    相关资源
    最近更新 更多