Ordered Unique Combinations [closed]

2020-05-10 10:16发布

问题:

I have the following class:

internal class Course
{
    public int CourseCode { get; set; }
    public string DeptCode { get; set; }
    public string Name { get; set; }
}

and the following code is the 2 dimensional array I have:

Course[][] courses = new Course[3][];
courses[0] = new Course[] {
   new Course() { CourseCode = 100, DeptCode = "EGR", Name = "EGR A" },
   new Course() { CourseCode = 100, DeptCode = "EGR", Name = "EGR B" }
};

courses[1] = new Course[] {
   new Course() { CourseCode = 200, DeptCode = "EN", Name = "EN A" }
};

courses[2] = new Course[] {
   new Course() { CourseCode = 300, DeptCode = "PHY", Name = "PHY A" }
};

What I want to do is get the different combinations that each item in a group could do with the other groups; for example with the previous code, the results would be:

1. EGR A - EN A - PHY A
2. EGR B - EN A - PHY A

Answers: To get the number of combinations possible, we can use Rule of Product, in the above case, the possible combinations will be (2 * 1 * 1) = 2 which is indeed the 2 combinations I wrote above.

LordTakkera has given the perfect answer, thank you so much!

回答1:

You could use a nested for loop:

for (int i = 0; i < courses[0].Length; i++)
{
   for (int j = 0; j < courses[1].Length; i++)
   {
     for (int k = 0; k < courses[2].Length; i++)
     {
         //Do whatever you need with the combo, accessed like:
         //courses[0][i], courses[1][j], courses[2][k]
     }
   }
}

Of course, this solution gets really messy the more nesting you need. If you need to go any deeper, I would use some kind of recursive function to traverse the collection and generate the combinations.

It would be something like:

class CombinationHelper
{
    public List<List<Course>> GetAllCombinations(Course[][] courses)
    {
            return GetCourseCombination(courses, 0);
    }

    public List<List<Course>> GetCourseCombination(Course[][] courses, int myIndex)
    {
        List<List<Course>> combos = new List<List<Course>>();

        for (int i = 0; i < courses[myIndex].Length; i++)
        {
            if (myIndex + 1 < courses.GetLength(0))
            {
               foreach (List<Course> combo in GetCourseCombination(courses, myIndex + 1))
               {
                  combo.Add(courses[myIndex][i]);
                  combos.Add(combo);
               }
            }
            else
            {
               List<Course> newCombination = new List<Course>() { courses[myIndex][i] };
               combos.Add(newCombination);
            }
        }
        return combos;
    }
}

I tested this (substituting "int" for "Course" to make verification easier) and it produced all 8 combinations (though not in order, recursion tends to do that. If I come up with the ordering code, I'll post, but it shouldn't be too difficult).

Recursive functions are hard enough for me to come up with, so my explanation won't be very good. Basically, we start by kicking the whole thing off with the "0" index (so that we start from the beginning). Then we iterate over the current array. If we aren't the last array in the "master" array, we recurse into the next sub-array. Otherwise, we create a new combination, add ourselves to it, and return.

As the recursive stack "unwinds" we add the generated combinations to our return list, add ourselves to it, and return again. Eventually the whole thing "unwinds" and you are left with one list of all the combinations.

Again, I'm sure that was a very confusing explanation, but recursive algorithms are (at least for me) inherently confusing. I would be happy to attempt to elaborate on any point you would like.



回答2:

Take a look at your second index - the 0 or 1. If you look only at that, you see a binary number from 0 to 7.

Count from 0 to 7, translate it to bits and get the combination pattern you need.