2014-12-19 6 views
0

중첩 루프를 사용하여 오브젝트 페인트에서 bool 조합의 모든 가능성을 비교하는 linq 표현식을 작성하는 코드 조각이 있습니다. 완벽하게 작동하지만 그림판에 속성을 계속 추가하려면 프로세스에 대한 루프를 계속 추가해야합니다. 재귀를 사용하도록 변환하고 싶습니다만, 문제가 있습니다. 누구나이 통찰력/출발점을 제공 할 수 있습니까?재귀를 사용하여 변환하는 데 문제가 있습니다

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, 즉 속성 당 2 개의 상태를 수행하고 있다고 생각했습니다. 그런 경우라면, 바이너리 산술의 편리함을 이용하여 정규 정수 카운터가 상태 열거를 처리하게 할 수 있습니다.

그러나 편의성이 없어도 그리 나쁘지 않습니다. 그것은 여전히 ​​동일한 기본 기술이지만 속성 수가 63보다 클 때 요구 사항으로 언급 한 추상화와 더 비슷한 작업을 수행하기 만하면됩니다.

먼저 추상화 된 카운터 클래스가 필요합니다. 다음은 바이트 단위의 카운터를 사용하는 버전입니다.이 버전은 속성 당 상태의 관점에서 과잉이지만 (필요한 3 개 대신 256 개 상태 지원) 바이트 또는 기타 유형으로 여러 카운터를 패킹하는 것보다 구현이 훨씬 쉽습니다.

각 카운터 counterCount 자리 숫자의 기초 counterMax에 자리 것처럼
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]; } } 
} 

상기는 카운터의 설정을 유지한다. Increment() 메서드는이 기본 숫자를 counterMax 숫자만큼 증가시키고 오버플로 할 때까지 true을 반환하므로 호출자가 가능한 모든 조합을 마쳤 으면이를 알 수 있습니다.

인덱서는 각 자릿수를 읽는 편리한 방법을 제공합니다.

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에 미리 사과) :

이제, 우리는 실제 Expression 열거를 구현하기 위해이 헬퍼 클래스를 사용할 수 있습니다.

즉, N 개의 부울 속성의 경우 속성을 모두 무시하는 옵션을 포함하여 3^N 개의 가능한 조합이 있습니다. 따라서이 기본 -3 숫자를 유지하기 위해 MultiCounter 클래스를 사용하여 0에서 3^N - 1까지 카운트를 반복하면됩니다.

두 가지 상태가있는 것처럼 편리하지는 않지만 추가 작업을 수행하면 관리 할 수있는 속성 수가 크게 제한되지 않습니다. MultiCounter 구현에서 배열의 2GB 제한에 도달하려면, 즉 20 억 개가 넘는 속성을 갖기 위해서는 먼저 몇 가지 근본적인 제한 사항을 먼저 해결해야합니다. :)

+0

저는 제 전화로 바로 이것을 확인할 수는 없지만, 사실, 거짓, 그리고 표현이 없으면 3^N을 의미 했습니까? – Mike

+0

아 ... 솔직히 말해서, 재산 당 세 가지 선택 사항이 있음을 알지 못했습니다. 나는 루프가 "<2"보다 "<= 2"라는 것을 놓쳤습니다. 그것은 조금 더 많은 작업이 필요하지만 동일한 기술이 적용됩니다. 이를 반영하기 위해 답을 업데이트하겠습니다. –

+0

매력처럼 작동했습니다! – Mike

관련 문제