2013-04-03 2 views
4

특정 유형의 목록이 n 개 있습니다. 내 요구 사항은 카디 전 곱을 만드는 것입니다. 어떻게해야합니까?n 개의 목록의 직교 곱

고정 수의 목록을 찾을 수는 있지만 목록의 동적 수는 나를 깜짝 놀라게합니다. 감사합니다.

+1

참조 : http://blogs.msdn.com/ 동적으로 당신이 필요 않는 코드를 생성하는 식 트리를 사용 b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx –

+0

참조 : http://stackoverflow.com/questions/3093622/generating-all-possible-combinations –

+0

@AnthonyPegram 나는이 글이 완성 되었기 때문에 다른 사람들이 비슷한 문제에 대한 해결책을 찾는데 도움이 될 것이기 때문에이 글을 답으로 쓸 것입니다. –

답변

-1

나는 ideea의이 : 여기

전체 솔루션입니다 :

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 
using System.Text; 

namespace testProjectExpressions 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     List<int> lst1 = new List<int>() 
         { 
          1, 
          2, 
          3 
         }; 


     List<int> lst2 = new List<int>() 
         { 
          4, 
          5, 
          6 
         }; 

     List<int> lst3 = new List<int>() 
         { 
          7, 
          8 
         }; 

     var fnc = CartesianProduct<int>(3); 

     var res = fnc(new[] {lst1, lst2, lst3 }); 

     foreach (var product in res) 
     { 
      for (int index = 0; index < product.Length; index++) 
      { 
       var productVar = product[index]; 
       if (index < product.Length - 1) 
        Console.Write(productVar + ","); 
       else 
       { 
        Console.WriteLine(productVar); 
       } 
      } 
     } 

     Console.ReadKey(); 
    } 

    private static Func<List<T>[], List<T[]>> CartesianProduct<T>(int howMany) 
    { 
     var inputArrayOfLists = Expression.Parameter(typeof (List<T>[]), "inputArgument"); 
     ParameterExpression[] loopVariables = new ParameterExpression[howMany]; 
     for (int index = 0; index < howMany; index++) 
      if (loopVariables[index] == null) 
       loopVariables[index] = Expression.Variable(typeof (T)); 

     List<Expression> finalStatements = new List<Expression>(); 

     // emit the create new object 
     var resultExpression = Expression.Variable(typeof (List<T[]>), "result"); 

     var assignExpression = Expression.Assign(resultExpression, Expression.New(typeof (List<T[]>))); 
     finalStatements.Add(assignExpression); 

     // the "Add" method 
     MethodInfo addMethod = typeof (List<T[]>).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public); 

     var EnumerableType = typeof(IEnumerable<T>); 
     MethodInfo GetEnumeratorMethod = EnumerableType.GetMethod("GetEnumerator"); 
     var moveNextMethod = typeof(IEnumerator).GetMethod("MoveNext"); 

     Expression recursiveExpression = null; 

     for (int index = 0; index < howMany; index++) 
     { 
      var variable = loopVariables[index]; 
      var indexAccess = Expression.ArrayIndex(inputArrayOfLists, Expression.Constant(index)); 
      var currentListExpression = indexAccess; 

      if (recursiveExpression == null) 
      { 
       var arrayVariable = Expression.Variable(typeof (T[]), "myArray"); 
       List<Expression> initExpressions = new List<Expression>(); 
       List<Expression> statements = new List<Expression>(); 

       var assign = Expression.Assign(arrayVariable, Expression.NewArrayInit(typeof (T), loopVariables)); 
       statements.Add(assign); 

       Expression callAddExpression = Expression.Call(resultExpression, addMethod, arrayVariable); 
       statements.Add(callAddExpression); 

       recursiveExpression = Expression.Block(new[] {arrayVariable}, statements); 
      } 

      recursiveExpression = ForEachExpression(typeof(IEnumerator<T>), GetEnumeratorMethod, moveNextMethod, 
       currentListExpression, variable, recursiveExpression); 
     } 

     finalStatements.Add(recursiveExpression); 
     finalStatements.Add(resultExpression); 

     List<ParameterExpression> blockParameters = new List<ParameterExpression>(loopVariables); 
     blockParameters.Add(resultExpression); 

     Expression block = Expression.Block(blockParameters, finalStatements); 

     var compiled = Expression.Lambda(block, inputArrayOfLists).Compile() as Func<List<T>[], List<T[]>>; 
     return compiled; 
    } 

    // compiles a foreach expression on the given collection! 
    public static Expression ForEachExpression(
      Type enumeratorType, 
      MethodInfo getEnumeratorMethod, 
      MethodInfo moveNextMethod, 
      Expression collection, 
      ParameterExpression loopVariable, 
      Expression loopContent) 
    { 
     var breakLabel = Expression.Label("STOP"); 
     var enumeratorVar = Expression.Variable(enumeratorType, "collectionEnumerator"); 
     var loop = Expression.Block(new[] { enumeratorVar }, 
      Expression.Assign(enumeratorVar, Expression.Call(collection, getEnumeratorMethod)), // var enumerator = collection.GetEnumerator(); 
      Expression.Loop(
       Expression.IfThenElse(
         Expression.Equal(Expression.Call(enumeratorVar, moveNextMethod), Expression.Constant(true)), // daca move_next e true 
         Expression.Block(new[] { loopVariable }, 
          Expression.Assign(loopVariable, Expression.Property(enumeratorVar, "Current")), // loopVariable = enumeratorVar.Current 
          loopContent // do some stuff with that entity 
         ), 
        Expression.Break(breakLabel) // jmp to break 
       ), 
      breakLabel) // break 
     ); 

     return loop; 
    } 
} 
}