使用linq中的where子句选择随机问题

时间:2017-08-11 08:24:03

标签: c# linq linq-to-sql

我需要为每个类别选择随机问题

private int[] categoryId = {1, 2, 3, 4, 5, ...};
private int[] questionsPerCategory = {3, 1, 6, 11, 7, ...};

在linq之前我使用

实现了它
SELECT TOP (@questionsPerCategory) * From Questions WHERE CategoriesID = @categoryId  AND 
InTest ='1' ORDER BY NEWID()

这也不正确,因为我必须为每个categoryId调用它。

如何在单个查询中使用linq获得所需的结果? 我需要的只是获取

  • 3个随机问题,categoryId = 1且InTest = true,
  • 1个随机问题,categoryId = 2且InTest = true,
  • 6个随机问题,categoryId = 3且InTest = true

依旧......

3 个答案:

答案 0 :(得分:3)

也许你想要这样的东西,你做一个小组然后从每个类别中选择你想要多少。

编辑:正如评论中的Enigmativity所指出的,Guid.NewGuid()不应仅仅因为唯一性而被用于随机性。要产生随机性,您应该咨询this StackOverflow post

Demo

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    private static int[] categoryIds = new int[] {1, 2, 3, 4, 5};
    private static int[] questionsPerCategory = {3, 1, 6, 11, 7};
    //Part of demo
    private static IEnumerable<QuestionVM> Questions = Enumerable.Range(0,100).Select(x=> new QuestionVM { Question = $"Question - {x}", CategoryId = (x % 5) + 1});


    public static void Main()
    {
        var questions = Questions.Where(x=> x.InTest).GroupBy(x=> x.CategoryId).SelectMany(x=> x.OrderBy(y=> Guid.NewGuid()).Take(GetQuestionTake(x.Key)));
        foreach(var question in questions)
            Console.WriteLine($"{question.Question} - CategoryId: {question.CategoryId}");  
    }

    ///Finds out how many questions it should take by doing a search and then picking the element in the same position
    private static int GetQuestionTake(int categoryId)
    {
        int element =  categoryIds.Select((x, i) => new { i, x }).FirstOrDefault(x => x.x == categoryId).i;
        return questionsPerCategory.ElementAtOrDefault(element);
    }
}


//Part of demo
public class QuestionVM
{
    public string Question {get;set;}
    public int CategoryId {get;set;}    
    public bool InTest {get;set;} = true;
}

答案 1 :(得分:3)

由于LINQ to SQL不支持Guid.NewGuid,因此首先需要使用Random row from Linq to Sql的接受答案中的技巧,通过将以下内容添加到您的NEWID功能来访问partial class YourDataContext { [Function(Name="NEWID", IsComposable=true)] public Guid Random() { // to prove not used by our C# code... throw new NotImplementedException(); } } 上下文类:

CategoryID

然后查询单var query = db.Questions .Where(e => e.CategoriesID == categoryId[i] && e.InTest) .OrderBy(e => db.Random()) .Take(questionsPerCategory[i]) 和问题计数将是:

UNION ALL

要获得所有类别/问题计数对的预期结果,您可以使用上述Concat i = 0..N的{​​{1}} var query = categoryId.Zip(questionsPerCategory, (catId, questions) => db.Questions .Where(q => q.CategoriesID == catId && q.InTest) .OrderBy(q => db.Random()) .Take(questions) ).Aggregate(Queryable.Concat) .ToList(); 来构建categoryId SQL查询:

import { trigger, animate, style, group, query, transition } from '@angular/animations';

export const baseAnimation =
    trigger('baseAnimation', [
      transition('acct => home', [
        query(':enter, :leave', style({ position: 'absolute', top: 0, left: 0, right: 0 })),
        query(':leave', style({ height: '*'})),
        query('.acct', [
            animate('300ms',
            style({ height: 0 }))
        ])
      ]),
      transition('home => acct', [
        query(':enter, :leave',
          style({ position: 'absolute', top: 0, left: 0, right: 0 })),
        query(':enter .acct', [
          style({ height: 0 }),
          animate('300ms', style({ height: '*' }))
        ])
      ])
    ])

这应该通过单个SQL查询产生所需的结果。当然,如果.acct的计数相对较小,它是适用的。

答案 2 :(得分:0)

一种常见的方式是按Guid.NewGuid()排序,以便扩展Crekate的答案。

.OrderBy(c=>Guid.NewGuid());