2014-12-19 78 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