2014-12-19 42 views
0

我有一段代码使用嵌套循环创建一个linq表达式,该表达式比较对象Paint中每个bool组合的可能性。它完美地工作,但如果我想继续添加属性到Paint,我将不得不继续添加for循环到流程。我想将其转换为使用递归,但我遇到了麻烦。任何人都可以为此提供一些见解/起点吗?将问题转换为使用递归

ParameterExpression param = Expression.Parameter(typeof(Paint), "t"); 

Expression exp = null; 

object f = false; 
object t = true; 

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

//Properties to compare 
MemberExpression memberA = Expression.Property(param, "BoolA"); 
MemberExpression memberB = Expression.Property(param, "BoolB"); 
MemberExpression memberC = Expression.Property(param, "BoolC"); 
MemberExpression memberD = Expression.Property(param, "BoolD"); 

//Loop 3 times to create expression using BoolA == true, BoolA == false, do not use BoolA 
for(int aa = 0; aa <= 2; aa++) 
{ 
    Expression aExp = null; 

    if (aa == 0) 
    { 
     aExp = Expression.Equal(memberA, Expression.Constant(f)); 
     expList.Add(aExp); 
    } 
    if(aa == 1) 
    { 
     aExp = Expression.Equal(memberA, Expression.Constant(t)); 
     expList.Add(aExp); 
    } 

    for (int bb = 0; bb <= 2; bb++) 
    { 
     Expression bExp = null; 

     if (bb == 0) 
     { 
      bExp = Expression.Equal(memberB, Expression.Constant(f)); 
      expList.Add(bExp); 
     } 
     if (bb == 1) 
     { 
      bExp = Expression.Equal(memberB, Expression.Constant(t)); 
      expList.Add(bExp); 
     } 

     for(int cc = 0; cc <= 2; cc++) 
     { 
      Expression cExp = null; 

      if (cc == 0) 
      { 
       cExp = Expression.Equal(memberC, Expression.Constant(f)); 
       expList.Add(cExp); 
      } 
      if(cc == 1) 
      { 
       cExp = Expression.Equal(memberC, Expression.Constant(t)); 
       expList.Add(cExp); 
      } 

      for (int dd = 0; dd <= 2; dd++) 
      { 
       Expression dExp = null; 

       if (dd == 0) 
       { 
        dExp = Expression.Equal(membeDr, Expression.Constant(f)); 
        expList.Add(dExp); 
       } 
       if (dd == 1) 
       { 
        dExp = Expression.Equal(memberD, Expression.Constant(t)); 
        expList.Add(dExp); 
       } 

       //Process expList 

       //remove expression to prepare to add its opposite in its place 
       expList.Remove(dExp); 
      } 
      expList.Remove(cExp); 
     } 
     expList.Remove(bExp); 
    } 
    expList.Remove(aExp); 
} 
+1

你不需要递归来实现这一点,也不需要嵌套循环。不幸的是,这个问题已经结束了,因为我认为这个问题很清楚,根本不宽泛,并且很容易回答。 –

+0

@PeterDuniho对于一个解决方案,你会提出什么建议,以便我可以研究它? – Mike

+0

在评论中很难解释,但基本思想是:维护一个计数器(如果你有32个或更少的属性,计数器可以简单地是一个'int')。从0开始,检查计数器中的每一位,以查看表达式是否应为“true”或“false”来构建要处理的表达式列表。处理后,清除列表,增加计数器,然后重新执行。继续,直到计数器的值为0x01 << count',其中'count'是您正在处理的属性数。将属性表达式保留在一个数组中,以便知道哪一个属于哪个位。 –

回答

1

你不需要递归来实现这一点,也不需要嵌套循环。我原本误读了这个问题,并认为你只是在做true/false,即每个房产两个州。如果是这样的话,你可以利用二进制算术的便利来让普通的整数计数器处理状态的枚举。

然而,即使没有那种方便,这也不算太坏。它仍然是相同的基本技巧,但是当您的属性数量高于63时,您只需简单地完成与我提到的抽象更类似的事情。

首先,我们需要抽象计数器类。这是一个使用字节计数器的版本,在每个属性状态方面都是过度的(支持256个状态,而不仅仅是你需要的3个状态),但是使得实现比将多个计数器打包成字节或其他类型容易得多:

class MultiCounter 
{ 
    private int _counterMax; 
    private byte[] _counters; 

    public MultiCounter(int counterCount, int counterMax) 
    { 
     _counterMax = counterMax; 
     _counters = new byte[counterCount]; 
    } 

    public bool Increment() 
    { 
     for (int i = 0; i < _counters.Length; i++) 
     { 
      if (++_counters[i] < _counterMax) 
      { 
       return true; 
      } 

      _counters[i] = 0; 
     } 

     return false; 
    } 

    public int this[int index] { get { return _counters[index]; } } 
} 

上述保持设置的计数器,如同每个计数器都与counterCount位的数字的基础counterMax数字。 Increment()方法递增此基数,返回true直到它溢出为止,这允许调用者知道何时所有可能的组合完成。

索引器提供了读取每个数字的便捷方法。现在

,我们可以用这个辅助类来实现实际Expression枚举:

MemberExpression[] memberExpressions = 
{ 
    Expression.Property(param, "BoolA"), 
    Expression.Property(param, "BoolB"), 
    Expression.Property(param, "BoolC"), 
    Expression.Property(param, "BoolD"), 
}; 

MultiCounter multiCounter = new MultiCounter(memberExpressions.Length, 3); 

List<Expression> expList = new List<Expression>(memberExpressions.Length); 

do 
{ 
    expList.Clear(); 

    for (int index = 0; index < memberExpressions.Length; index++) 
    { 
     int propertyCounter = multiCounter[index]; 

     if (propertyCounter == 2) 
     { 
      continue; 
     } 

     expList.Add(Expression.Equal(
      memberExpressions[index], 
      Expression.Constant(propertyCounter == 1))); 
    } 

    // Process expList here 

} while (multiCounter.Increment()); 

(提前拼写错误或其他错误&hellip道歉;上面是仍然只是输入到我的浏览器用于说明目的)。

换句话说,对于N布尔属性,您有3^N个可能的组合,包括完全忽略该属性的选项。因此,只需使用MultiCounter类来简单地迭代0至3^N-1的计数即可保持此基数为3的数字。

虽然这并不像您刚才的两种状态那样方便,但有一件好事就是完成了额外的工作,现在您对可管理的属性数量没有明显的限制。要达到MultiCounter实现中阵列的2GB限制,即拥有超过250亿个属性,您必须首先解决一些其他基本限制。 :)

+0

我在我的手机上,所以不能马上检查这个,但是你的意思是3^N为真,假,没有表达? – Mike

+0

啊...说实话,我没有注意到你每个房产都有三个选择。我错过了循环是“<= 2”而不是“<2”。这将涉及更多的工作,但同样的技术适用。我会更新答案以适应这一点。 –

+0

工作就像一个魅力! – Mike