2013-07-14 3 views
8

上記の解決策とは異なり、リスト項目は各行に対して1回しか表示できません。複数のリストのすべての組み合わせを取得する方法<int>

これは私のスパの予約システム用です。異なる従業員が異なる治療を行うことができます。

私にはList<List<int>>があります。これらは、予約された治療を行うことができるセラピストです。私は数だけに表示できるすべての可能な組み合わせを見てみたいと思います

{1, 3, 6}, //Booking 1 
{1, 2, 6}, //Booking 2 
{1},  //Booking 3 
{2,3}  //Booking 4 

各リスト(予約)は、この(これらは予約を行うことができセラピストている)のような整数の数が含まれています一箇所。上記リストは、二つの可能なombinationsは次のようになります

6,2,1,3又は第一の組み合わせのためのものである3,6,1,2

  • 予約1 :セラピスト6
  • 予約2:セラピスト2
  • 予約3:セラピスト1
  • 予約4:セラピスト3

これは質問が少し明確になることを期待しています。

+2

あなたはどのようにこれらの2つの組み合わせを考え出しましたか? – SamiHuutoniemi

+0

@SamHuutoniemiまあ、私は他の人と会うことはできないのですか? – ekenman

+0

いいえ、その疑問の数字はいくつかの場所にある可能性があります。だから、すべての組み合わせがそこで受け入れられるだろう。 – ekenman

答えて

2

このソリューションは、効率的にはほど遠いです:

private static void Main() 
    { 
     List<List<int>> list = new List<List<int>> 
      { 
       new List<int>() {1, 3, 6}, //Booking 1 
       new List<int>() {1, 2, 6}, //Booking 2 
       new List<int>() {1}, //Booking 3 
       new List<int>() {2, 3} 
      }; 
     List<int[]> solutions = new List<int[]>(); 
     int[] solution = new int[list.Count]; 
     Solve(list, solutions, solution); 
    } 

    private static void Solve(List<List<int>> list, List<int[]> solutions, int[] solution) 
    { 
     if (solution.All(i => i != 0) && !solutions.Any(s => s.SequenceEqual(solution))) 
      solutions.Add(solution); 
     for (int i = 0; i < list.Count; i++) 
     { 
      if (solution[i] != 0) 
       continue; // a caller up the hierarchy set this index to be a number 
      for (int j = 0; j < list[i].Count; j++) 
      { 
       if (solution.Contains(list[i][j])) 
        continue; 
       var solutionCopy = solution.ToArray(); 
       solutionCopy[i] = list[i][j]; 
       Solve(list, solutions, solutionCopy); 
      } 
     } 
    } 

これは、動的プログラミングをより効率的に解くことができるように聞こえるが、私は、関連するコースを取ったので、それがしばらくしています。再帰によって

+0

ありがとうytoledano!それほど多くはないので、パフォーマンスは問題ではありません。 – ekenman

4

解決:

static IEnumerable<List<int>> GetCombinations(IEnumerable<List<int>> lists, IEnumerable<int> selected) 
{ 
    if (lists.Any()) 
    { 
     var remainingLists = lists.Skip(1); 
     foreach (var item in lists.First().Where(x => !selected.Contains(x))) 
      foreach (var combo in GetCombinations(remainingLists, selected.Concat(new int[] { item }))) 
       yield return combo; 
    } 
    else 
    { 
     yield return selected.ToList(); 
    } 
} 

static void Main(string[] args) 
{ 
    List<List<int>> lists = new List<List<int>> 
    { 
     new List<int> { 1, 3, 6 }, 
     new List<int> { 1, 2, 6 }, 
     new List<int> { 1 }, 
     new List<int> { 2, 3 } 
    }; 

    var combos = GetCombinations(lists, new List<int>()).Distinct(); 

    foreach (var combo in combos) 
     Console.WriteLine("{ " + string.Join(", ", combo.Select(x => x.ToString())) + " }"); 

    return; 
} 

出力:

{ 3, 6, 1, 2 } 
{ 6, 2, 1, 3 } 
1

この問題を見て簡単な方法は、値のリスト、内のすべての値のすべての組み合わせから選択するだろう組み合わせはユニークです。

まず、すべての値の組み合わせが何であるかを把握します。

public static IEnumerable<IList<T>> Combinations<T>(IEnumerable<IList<T>> collections) 
{ 
    if (collections.Count() == 1) 
    { 
     foreach (var item in collections.Single()) 
      yield return new List<T> { item }; 
    } 
    else if (collections.Count() > 1) 
    { 
     foreach (var item in collections.First()) 
     foreach (var tail in Combinations(collections.Skip(1))) 
      yield return new[] { item }.Concat(tail).ToList(); 
    } 
} 

次に、すべての値が一意であるかどうかを判断する方法が必要です。それを理解する簡単な方法は、異なる値のカウントがすべての値のカウントと等しいかどうかをチェックすることです。

public static bool AllUnique<T>(IEnumerable<T> collection) 
{ 
    return collection.Distinct().Count() == collection.Count(); 
} 

これですべてが完成したら、すべてまとめてください。

var collections = new[] 
{ 
    new List<int> { 1, 3, 6 }, 
    new List<int> { 1, 2, 6 }, 
    new List<int> { 1 }, 
    new List<int> { 2, 3 }, 
}; 
var results = 
    from combination in Combinations(collections) 
    where AllUnique(combination) 
    select combination; 
// results: 
// 3,6,1,2 
// 6,2,1,3 
関連する問題