I have a table
Questions -> Question(string), Difficulty (int, 1-10)
I need to create a method, that as the title mentions, take
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:
///
/// Gets lists of numQuestions length of all combinations
/// of questions whose difficulties add up to sumDifficulty
///
/// The list of questions to search
/// The number of questions required
/// The amount that the difficulties should sum to
///
public static List> GetQuestions(List questions,
int numQuestions, int sumDifficulty)
{
if (questions == null) throw new ArgumentNullException("questions");
var results = new List>();
// 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 {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(),
numQuestions, results);
return results;
}
And then the recursive method that does the heavy lifting:
private static void GetSumsRecursively(IReadOnlyList questions,
int sumDifficulty, List candidates, int numQuestions,
ICollection> 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();
for (int j = i + 1; j < questions.Count; j++)
{
remaining.Add(questions[j]);
}
var filteredCandidates = new List(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();
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:
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; }
}