我已经生成了一个函数来取回一组随机的提交,具体取决于传递给它的数量,但是我担心即使现在通过少量数据传递大量数据,它也会变得有效并导致问题。
是否有更有效的方法来做以下事情?
public List<Submission> GetRandomWinners(int id)
{
List<Submission> submissions = new List<Submission>();
int amount = (DbContext().Competitions
.Where(s => s.CompetitionId == id).FirstOrDefault()).NumberWinners;
for (int i = 1 ; i <= amount; i++)
{
bool added = false;
while (!added)
{
bool found = false;
var randSubmissions = DbContext().Submissions
.Where(s => s.CompetitionId == id && s.CorrectAnswer).ToList();
int count = randSubmissions.Count();
int index = new Random().Next(count);
foreach (var sub in submissions)
{
if (sub == randSubmissions.Skip(index).FirstOrDefault())
found = true;
}
if (!found)
{
submissions.Add(randSubmissions.Skip(index).FirstOrDefault());
added = true;
}
}
}
return submissions;
}
正如我所说,我已经完全正常工作并带回了想要的结果。只是因为我不喜欢那里的foreach
和while
支票而且我的头脑刚刚变成糊状,现在试图提出上述解决方案。
答案 0 :(得分:6)
(请仔细阅读,因为要考虑效率的不同方面。)
确实有更简单的方法 - 特别是,您实际上不需要重复执行查询以获得正确的答案。为什么要在循环中获取randSubmissions
?您还应该查看ElementAt
以避免Skip
和FirstOrDefault
- 并且请记住,由于randSubmissions
是一个列表,您可以使用常规列表操作,例如{ {1}}属性和索引器!
首先想到的选项是执行部分随机播放。 modified Fisher-Yates shuffle的Stack Overflow上有大量示例。您可以非常轻松地修改该代码,以避免混乱整个列表 - 只需将其随机播放,直到您拥有所需数量的随机元素为止。事实上,这些天我可能会稍微改变一下,你可以调用:
Count
例如:
return correctSubmissions.Shuffle(random).Take(amount).ToList();
鉴于上述方法,您的GetRandomWinners方法将如下所示:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
for (int i = 0; i < elements.Length; i++)
{
// Find an item we haven't returned yet
int swapIndex = i + rng.Next(elements.Length - i);
T tmp = elements[i];
yield return elements[swapIndex];
elements[swapIndex] = tmp;
// Note that we don't need to copy the value into elements[i],
// as we'll never use that value again.
}
}
我建议您不要在方法中创建public List<Submission> GetRandomWinners(int competitionId, Random rng)
{
List<Submission> submissions = new List<Submission>();
int winnerCount = DbContext().Competitions
.Single(s => s.CompetitionId == competitionId)
.NumberWinners;
var correctEntries = DbContext().Submissions
.Where(s => s.CompetitionId == id &&
s.CorrectAnswer)
.ToList();
return correctEntries.Shuffle(rng).Take(winnerCount).ToList();
}
的新实例。我有article on preferred ways of using Random
你可能会觉得有用。
您可能需要考虑的另一个选择是计算出正确条目的 count 而不是全部取出它们,然后通过计算随机选择的“行ID”然后使用{来计算获胜条目重复{1}}(顺序一致)。或者,不要拉动完整的提交,而只需提取他们的ID。随机抽取ID以随机选择(您放入Random
,然后使用以下内容:
ElementAt
我相信这会在SQL中使用“IN”子句,尽管可以像这样检索多少条目有限制。
即使您有100,000个正确的条目和3个获胜者,您也只能获取100,000个ID,但会获得3个完整记录。希望有意义!