【问题标题】:Partial short circuit boolean evaluation in Javascript or C#Javascript 或 C# 中的部分短路布尔求值
【发布时间】:2014-06-02 17:48:01
【问题描述】:

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

或者换个说法;是否可以评估表达式以使其返回“true”、“false”或“maybe”?其中“可能”表示需要更多数据。

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

例如,考虑以下表达式:

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

有几种可能: 如果ab已经被检索到,但c还没有被检索到:

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

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

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

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

有人有想法吗?过程、函数、算法?

【问题讨论】:

  • 通常所有这些快捷方式在迭代中加起来以节省总任务时间,但不确定如何在总时间方面对其进行更多优化。您可以通过运行两次传递来使其响应更快:一次计算是否需要 c,第二次获取需要它的事务的更多详细信息。
  • 你有代表这些表达式的数据结构吗?然后您可以编写一个简单的解释器,将给出 true/false/unknown 作为结果,“unknown”表示需要更多数据(例如,如果 c = 3,c = 3 为 true,如果 c = 2,则为 false,如果 c尚未检索)。 “未知”将通过布尔运算符适当地传播。

标签: c# javascript boolean evaluation


【解决方案1】:

因此,要涵盖您非常具体的代码,您可以简单地使用以下代码:

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;

【讨论】:

  • 这绝对是布尔构造的一个有价值的实现,如果不需要计算条件,可以使用它来推迟冗长的过程。通过扩展,解决方案的彻底性有助于回答“有没有办法......?”的 OP 问题。简短的回答是“是的,但需要做很多工作,而且你不会喜欢它。”简短的回答是“不,在大多数情况下没有。”
【解决方案2】:

假设 a、b、c 在加载后为真,并且事先为假(或者可能 a、b、c 包含您可以检查的“已加载”属性):

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-10
    • 2012-06-05
    • 2013-10-02
    • 2011-08-04
    • 2019-08-27
    • 2011-12-01
    • 1970-01-01
    相关资源
    最近更新 更多