Javascript或C#中的部分短路布尔评估

时间:2014-06-02 17:48:02

标签: c# javascript boolean evaluation

有没有办法在JavaScript或C#中确定逻辑表达式的结果 已检索到所有变量的值?

或者换句话说;可以对某个表达式进行评估,使其返回“真假”,“假”,“或者可能”等。其中可能是'表示需要更多数据。

解释:我有一个过程,需要一些时间从数据库后端检索数据,我想看看我们是否可以跳过检索某些数据,如果没有必要。但逻辑表达式已经预先确定,不能更改或拆分。

例如,请考虑以下表达式:

((a = 1) and (b = 2)) or (c = 3)

有几种可能性: 如果已检索到ab,但尚未检索到c

  • 如果a=1b=2,那么表达式将始终返回true,我可以跳过检索c
  • 的值
  • 如果a=0b=2那么第一部分将为false,我需要检索c的值才能确定结果

如果已检索到c,但尚未检索到ab

  • 如果c=3,那么表达式将始终返回true,我可以跳过检索ab的值。
  • 如果c=2,则第一部分将为false,我需要检索ab的值,以便能够确定结果

在这些情况下,只要知道结果已经确定,或者需要更多数据就可以显着加快流程。

有人有想法吗?一个过程,功能,算法?

2 个答案:

答案 0 :(得分:0)

为了涵盖您的特定代码,您只需使用以下内容:

if(CHasValue())
    return (c == 3) or ((a == 1) and (b == 2))
else
    return ((a == 1) and (b == 2)) or (c == 3)

操作员的短路将照顾其余部分。

但是,对于更复杂的表达式,这并不能很好地扩展。为了真正覆盖任何任意布尔表达式,您确实需要创建自己的新类型和相应的布尔运算符。

我们将从定义布尔值的接口开始,该布尔值可能已经或可能没有计算其值:

public interface IComputableBoolean
{
    public bool Value { get; }
    public bool ValueComputed { get; }
}

第一个实施很容易;它是一个可计算的布尔值,表示我们已经知道的值:

public class ComputedBoolean : IComputableBoolean
{
    public ComputedBoolean(bool value)
    {
        Value = value;
    }
    public bool Value { get; private set; }
    public bool ValueComputed { get { return true; } }
}

然后是稍微复杂的情况,即基于函数生成的布尔值(可能是可能长时间运行或具有副作用的东西)。它需要一个委托来计算表达式,在第一次请求值时对其进行评估,然后从那时起返回一个缓存值(并指示它已经计算了它的值)。

public class DeferredBoolean : IComputableBoolean
{
    private Func<bool> generator;
    private bool? value = null;
    public DeferredBoolean(Func<bool> generator)
    {
        this.generator = generator;
    }
    public bool Value
    {
        get
        {
            if (value != null)
                return value.Value;
            else
            {
                value = generator();
                return value.Value;
            }

        }
    }
    public bool ValueComputed { get { return value != null; } }
}

现在我们只需要创建适用于此接口的AndOrNot方法。他们应首先检查是否计算了足够的值以使其短路,如果不是,则应创建表示值的计算的延迟布尔值。这种延迟值的传播很重要,因为它允许组合复杂的布尔表达式,并且仍然可以用最少量的计算进行适当的短路。

public static IComputableBoolean And(
    this IComputableBoolean first,
    IComputableBoolean second)
{
    if (first.ValueComputed && !first.Value ||
        second.ValueComputed && !second.Value)
        return new ComputedBoolean(false);
    else
        return new DeferredBoolean(() => first.Value && second.Value);
}

public static IComputableBoolean Or(
    this IComputableBoolean first,
    IComputableBoolean second)
{
    if (first.ValueComputed && first.Value ||
        second.ValueComputed && second.Value)
        return new ComputedBoolean(true);
    else
        return new DeferredBoolean(() => first.Value && second.Value);
}

Not操作有点不同,因为它根本不会短路,但它仍然很重要,因为它继续推迟对给定布尔表达式的评估,因为它最终可能不需要。

public static IComputableBoolean Not(
    this IComputableBoolean boolean)
{
    if (boolean.ValueComputed)
        return new ComputedBoolean(boolean.Value);
    else
        return new DeferredBoolean(() => boolean.Value);
}

我们现在可以代表您喜欢的表达式(使用实际的长时间运行操作来根据需要计算ab和/或c

var a = new DeferredBoolean(() => false);
var b = new DeferredBoolean(() => true);
var c = new DeferredBoolean(() => false);

var expression = a.And(b).Or(c);
bool result = expression.Value;

答案 1 :(得分:-2)

假设a,b,c一旦加载就变得真实,并且预先假装(或者a,b,c包含&#34;加载的&#34;属性,你可以检查):

var isValid = false;
if (a && b) {
  if (a == 1 && b == 2) {
    isValid = true;
  }
}
if (!isValid && c) {
  if (c == 3) {
    isValid = true;
  }
}