Javascript中的表达式树求值

Javascript中的表达式树求值,javascript,recursion,expression-trees,Javascript,Recursion,Expression Trees,我有由嵌套的逻辑表达式对象组成的输入 例: 这相当于((false&&true&&true)| | | | | | false | | | |(true&&true))| | true) 我们需要写一个函数来计算这个 方法: 转到最内层,首先对其进行评估,然后移动到顶部 var expressionEvaluator = function(opArr){ var hasChildObjects = function(arr){ if(Arr

我有由嵌套的逻辑表达式对象组成的输入

例:

这相当于
((false&&true&&true)| | | | | | false | | | |(true&&true))| | true)

我们需要写一个函数来计算这个

方法:

转到最内层,首先对其进行评估,然后移动到顶部

var expressionEvaluator = function(opArr){
            var hasChildObjects = function(arr){
                if(Array.isArray(arr)){
                    return arr.some(function(obj){
                        return typeof(obj) === 'object';
                    });
                }
                else if(typeof(arr) === 'object'){
                    return true;
                }
            };
            var evaluateArr = function(list, operator){
                var result;
                if(operator === 'AND'){
                    result = true;
                    for(var i = 0; i<list.length; i++){
                        if(!list[i]){
                            result = false;
                        }
                    }
                }
                else if(operator === 'OR'){
                    result = false;
                    for(var i = 0; i<list.length; i++){
                        if(list[i]){
                            result = true;
                        }
                    }
                }
                return result;
            };
            var iterate = function(opArr){
                Object.keys(opArr).forEach(function(k){
                    if(hasChildObjects(opArr[k])){
                        iterate(opArr[k]);
                    }
                    else{
                        opArr = evaluateArr(opArr[k], k);
                    }
                });
            };
            iterate(opArr);
            return result;
        }
var expressionEvaluator=函数(opArr){
var hasChildObjects=函数(arr){
if(数组isArray(arr)){
返回arr.some(功能(obj){
返回类型(obj)==“对象”;
});
}
else if(typeof(arr)==“object”){
返回true;
}
};
var evaluateArr=函数(列表,运算符){
var结果;
如果(运算符=='和'){
结果=真;

对于(var i=0;i,可以使用一个简单的递归函数

  • 如果当前对象具有
    键,则检查数组中的项是否为
    truthy
  • 如果
    ,检查项目是否为
    truthy
  • 如果数组中的某个项是对象,则递归调用该对象上的函数以获取其值
const input={OR:[{和:[false,true,true]},{OR:[true,false,false,{和:[true,true]}]},true]};
函数求值({OR,AND}){
如果(或)
返回或.some(c=>typeof c===“object”?计算(c):c)
若(及)
返回和.every(c=>typeof c===“object”?计算(c):c)
}
console.log(evaluate(input))
函数evalOBJ(obj){
让结果=真;
如果(目标或){
结果=假;
用于(对象或的常数v){
if(typeof v==='object'){
结果=结果| | evalOBJ(v);
}否则{
结果=结果| | v;
}
}
}否则,如果(目标和){
用于(对象和的常数v){
if(typeof v==='object'){
结果=结果和评估(v);
}否则{
结果=结果&v;
}
}
}
返回结果;
}

这基本上与操作相同,但变体在
evaluate
和操作符函数之间使用相互递归。主要好处是遍历树
evaluate
的算法与实际使用的操作符分离。如果需要,只需添加将它们发送给
操作员

const运算符={
“或”:arr=>arr.some(评估),
“和”:arr=>arr.every(评估),
}
功能评估(输入){
if(输入类型!==“对象”)
返回输入;
常量[op,value]=对象项(输入)[0];
返回运算符[op](值);
}
测试(正确);
测试(假);
测试({“或”:[假,真]});
测试({“或”:[假,假]});
测试({“AND”:[true,true]});
测试({“AND”:[false,true]});
试验({
'或':[
{
“和”:[
假,真,真
]
},
{
'或':[
真,假,假,{
'和':[对,对]
}
]
},
真的
]
})
功能测试(输入){
log(`evaluation:${JSON.stringify(输入,未定义,2)}
结果:${evaluate(input)}`)

}
不确定这是否是一个好的解决方案,但我认为我们可以有点“懒惰”,避免不必要的递归,这取决于表达式树的大小

在以下表达式中,无需同时计算A和B,因为C已为真:

{OR:[{/*…*/},{/*…*/},true]}
//    ^            ^            ^
//A、B、C
同样,也不需要同时评估A和B,因为C已经为假:

{AND:[{/*…*/},{/*…*/},false]}
//     ^            ^            ^
//A、B、C
考虑到这一点,我想出了以下代码:

const lazy\u或=exp=>exp.find(e=>e==true);
const lazy_and=exp=>exp.find(e=>e==false);
常数评估=
exp=>
exp的类型==“布尔”?exp
:exp.OR&&lazy\u或(exp.OR)?真
:exp.OR?exp.OR.some(评估)
:exp.AND&&lazy_和(exp.AND)==false?false
:exp.AND.every(评估);

这是主题的另一个变体:

const evaluate=(树)=>
树的类型==“布尔”
?树
:“或”在树上
?树或某些(评估)
:“和”在树上
?树和每个(评估)
:false//或抛出错误?
常量树={OR:[{和:[假,真,真]},{OR:[真,假,假,{和:[真,真]},真]}

log(evaluate(tree))
甚至可以是
(或??和)[或'some':'every'](…)
,尽管我知道这不是代码golf@adiga我们还可以为任何键、数组值添加空/未定义检查吗?@user544079尝试用
对象(c)替换
typeof c==='object'
===c
我对优化概念的关注是,如果我们立即检查早期的优化,有时短路速度会更快:
{或:[false,{和:[true,true]},false,false,…(一百万次)…false]}
。在不知道布尔和对象之间的平衡的情况下,这似乎只是猜测。@ScottSauyet这是公平的。我不认为我的答案特别好,但我认为提到它会很有用(没有其他人这么做,也许是出于一个很好的理由)。但是同样的论点也可以用于
{或:[false,{或:[false,{或:[false,{false,{…(深度嵌套)…}]},true]}
。你是对的,虽然这只是猜测和希望最好。是的,这就是我的意思。只有当你对dat了解更多时,这种优化才有用
var expressionEvaluator = function(opArr){
            var hasChildObjects = function(arr){
                if(Array.isArray(arr)){
                    return arr.some(function(obj){
                        return typeof(obj) === 'object';
                    });
                }
                else if(typeof(arr) === 'object'){
                    return true;
                }
            };
            var evaluateArr = function(list, operator){
                var result;
                if(operator === 'AND'){
                    result = true;
                    for(var i = 0; i<list.length; i++){
                        if(!list[i]){
                            result = false;
                        }
                    }
                }
                else if(operator === 'OR'){
                    result = false;
                    for(var i = 0; i<list.length; i++){
                        if(list[i]){
                            result = true;
                        }
                    }
                }
                return result;
            };
            var iterate = function(opArr){
                Object.keys(opArr).forEach(function(k){
                    if(hasChildObjects(opArr[k])){
                        iterate(opArr[k]);
                    }
                    else{
                        opArr = evaluateArr(opArr[k], k);
                    }
                });
            };
            iterate(opArr);
            return result;
        }