简体   繁体   English

如何提出X个问题,总结Y个难度

[英]How to take X amount of questions, that sum up Y amount of difficulty

I have a table 我有桌子

Questions -> Question(string), Difficulty (int, 1-10) 问题->问题(字符串),难度(int,1-10)

I need to create a method, that as the title mentions, takes X amount of questions, whose difficulty should sum up Y . 我需要创建一个方法,正如标题所述,该方法要处理X个问题,其难度应总结为Y

For example: 例如:

getQuestions(2,10) -> Question1 (diff: 4), Question2 (diff: 6) getQuestions(2,10) -> Question1(diff:4),Question2(diff:6)

getQuestions(3,15) -> Question3 (diff: 5), Question4 (diff: 5), Question5 (diff: 5) getQuestions(3,15) -> Question3(diff:5),Question4(diff:5),Question5(diff:5)

How can I achieve something like this with LINQ? 如何使用LINQ实现类似的目标?

Here's one way to do it, using a modified version of the recursive solution found here: Finding all possible combinations of numbers to reach a given sum 这是一种方法,使用此处找到的递归解决方案的修改版: 查找所有可能的数字组合以达到给定的总和

First, a public method that will do some quick validation and then call a recursive method to get the results: 首先,将执行一些快速验证的公共方法,然后调用递归方法以获取结果:

/// <summary>
/// Gets lists of numQuestions length of all combinations 
/// of questions whose difficulties add up to sumDifficulty
/// </summary>
/// <param name="questions">The list of questions to search</param>
/// <param name="numQuestions">The number of questions required</param>
/// <param name="sumDifficulty">The amount that the difficulties should sum to</param>
/// <returns></returns>
public static List<List<Question>> GetQuestions(List<Question> questions,
    int numQuestions, int sumDifficulty)
{
    if (questions == null) throw new ArgumentNullException("questions");

    var results = new List<List<Question>>();

    // Fail fast argument validation
    if (numQuestions < 1 || 
        numQuestions > questions.Count ||
        sumDifficulty < numQuestions * Question.MinDifficulty ||
        sumDifficulty > numQuestions * Question.MaxDifficulty)
    {
        return results;
    }

    // If we only need single questions, no need to do any recursion
    if (numQuestions == 1)
    {
        results.AddRange(questions.Where(q => q.Difficulty == sumDifficulty)
            .Select(q => new List<Question> {q}));

        return results;
    }

    // We can remove any questions who have a difficulty that's higher
    // than the sumDifficulty minus the number of questions plus one
    var candidateQuestions =
        questions.Where(q => q.Difficulty <= sumDifficulty - numQuestions + 1)
            .ToList();

    if (!candidateQuestions.Any())
    {
        return results;
    }

    GetSumsRecursively(candidateQuestions, sumDifficulty, new List<Question>(), 
        numQuestions, results);

    return results;
}

And then the recursive method that does the heavy lifting: 然后执行繁重工作的递归方法:

private static void GetSumsRecursively(IReadOnlyList<Question> questions, 
    int sumDifficulty, List<Question> candidates, int numQuestions, 
    ICollection<List<Question>> results)
{
    int candidateSum = candidates.Sum(x => x.Difficulty);

    if (candidateSum == sumDifficulty && candidates.Count == numQuestions)
    {
        results.Add(candidates);
    }

    if (candidateSum >= sumDifficulty)
        return;

    for (int i = 0; i < questions.Count; i++)
    {
        var remaining = new List<Question>();

        for (int j = i + 1; j < questions.Count; j++)
        {
            remaining.Add(questions[j]);
        }

        var filteredCandidates = new List<Question>(candidates) {questions[i]};

        GetSumsRecursively(remaining, sumDifficulty, filteredCandidates, 
            numQuestions, results);
    }
}

Here's an example usage: 这是一个示例用法:

public static void Main()
{
    const int numberOfQuestions = 3;
    const int sumOfDifficulty = 15;

    // Since I don't have your table, I'm using a list of objects to fake it
    var questions = new List<Question>();
    for (int i = 1; i < 11; i++)
    {
        questions.Add(new Question {Difficulty = i % 10 + 1, 
            QuestionString = "Question #" + i});
    }

    var results = GetQuestions(questions, numberOfQuestions, sumOfDifficulty);

    // Write output to console to verify results
    foreach (var result in results)
    {
        Console.WriteLine("{0} = {1}", string.Join(" + ", 
            result.Select(r => r.Difficulty)), sumOfDifficulty);
    }
}

And just so you have everything to make this work, here's my Question class used to fake your table: 这样您就可以完成所有工作,这是我的Question类,用于伪造您的表:

internal class Question
{
    public const int MinDifficulty = 1;
    public const int MaxDifficulty = 10;
    private int _difficulty;

    public int Difficulty
    {
        get { return _difficulty; }
        set
        {
            if (value < MinDifficulty) _difficulty = MinDifficulty;
            else if (value > MaxDifficulty) _difficulty = MaxDifficulty;
            else _difficulty = value;
        }
    }

    public string QuestionString { get; set; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM