转换为使用递归时出现问题
本文关键字:问题 递归 转换 | 更新日期: 2023-09-27 18:34:41
我有一段代码,它使用嵌套循环创建一个 linq 表达式,该表达式比较对象 Paint 中布尔组合的所有可能性。 它运行良好,但如果我想继续向 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);
}
你不需要递归来实现这一点,也不需要嵌套循环。我最初误读了这个问题,并认为您只是在做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()
方法递增此基数counterMax
,返回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());
(对于拼写错误或其他错误,请提前道歉......以上内容仍然只是为了说明目的而输入到我的浏览器中(。
换句话说,对于 N 个布尔属性,您有 3^N 种可能的组合,包括完全忽略该属性的选项。因此,只需迭代从 0 到 3^N - 1 的计数,使用 MultiCounter
类来维护这个以 3 为底的数字。
虽然这并不像您只有两种状态那样方便,但一件好事是,在完成了额外的工作之后,现在您对可以管理的属性数量没有显着限制。为了达到MultiCounter
实现中数组的 2GB 限制,即拥有 2+ 十亿个属性,您必须首先以某种方式绕过许多其他基本限制。:)