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;
}