c# - n 个列表的笛卡尔积

标签 c# .net

这个问题在这里已经有了答案:





Generating all Possible Combinations

(13 个回答)


去年关闭。




我有 n 个特定类型的列表,我的要求是从它们创建笛卡尔积。我该怎么做。

我可以找出静态数量的列表,但动态数量的列表让我感到惊讶。
感谢您在这方面的帮助。

最佳答案

我有一个想法:使用表达式树动态生成满足您需求的代码:

这是一个完整的解决方案:

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;
    }
}
}

关于c# - n 个列表的笛卡尔积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15776763/

相关文章:

.net - 你总是为新对象创建一个变量吗?

c# - 将列表<baseclass> 转换为列表<衍生类>

c# - .Net 项目总是重建,而不是由 CopyLocal 属性引起的最新

c# - 有没有办法获取 ListView 中子项的数量?

.net - 在 .net 中重用数据集

java - 无法使用 ksoap2 序列化日期

c# - 从 C# 执行 BC 计算

c# - SQL Server 中的 GUID

c# - 奇怪的动态类型参数问题

c# - 您能否确认 NHibernate 术语中的术语 'Save' 代表 INSERT?