[英]How to evaluate a string as expression with a window object in Javascript
[英]Evaluate expression tree in Javascript
我的輸入由嵌套的邏輯表達式對象組成
前任:
var obj = {
'OR': [
{
'AND': [
false, true, true
]
},
{
'OR': [
true, false, false, {
'AND': [true, true]
}
]
},
true
]
};
相當於((false && true && true) || (true || false || false || (true && true)) || true)
我們需要編寫一個 function 來計算這個
方法:
Go 到最內層並先評估它,移動到頂部
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;
}
我能夠到達最里面的 object 並對其進行評估,但不能回到最頂層並評估整個表達式 object。
您可以使用簡單的遞歸 function。
truthy
有OR
鍵,則檢查數組中的some
項是否為真。AND
,檢查every
項目是否truthy
。 const input={OR:[{AND:[false,true,true]},{OR:[true,false,false,{AND:[true,true]}]},true]}; function evaluate({ OR, AND }) { if (OR) return OR.some(c => typeof c === 'object'? evaluate(c): c) if (AND) return AND.every(c => typeof c === 'object'? evaluate(c): c) } console.log(evaluate(input))
由於回調函數相同,您還可以獲取對變量的操作並動態調用它:
function evaluate({ OR, AND }) {
const array = OR ?? AND,
operation = OR ? 'some' : 'every';
return array[operation](c => typeof c === 'object' ? evaluate(c) : c)
}
或者
const evaluate = ({ OR, AND }) => OR ? OR.some(callback) : AND.every(callback),
callback = c => typeof c === 'object' ? evaluate(c) : c
這里主題的另一個變體:
const evaluate = (tree) => typeof tree === 'boolean'? tree: 'OR' in tree? tree.OR.some (evaluate): 'AND' in tree? tree.AND.every (evaluate): false // or throw an error? const tree = {OR: [{AND: [false, true, true]}, {OR: [true, false, false, {AND: [true, true]}]}, true]} console.log (evaluate (tree))
如果是 boolean, evaluate
返回提供的值。 否則,它會檢查'OR'
或'AND'
節點,並適當地處理它們。 對於非良好的樹木,最后有一個包羅萬象的東西。 這里我返回false
,但您可能會拋出錯誤,返回null
或其他內容。
如果您不需要所有內容,可以將其簡化為單行:
const evaluate = (tree) =>
typeof tree == 'boolean' ? tree: tree.OR ? tree.OR .some (evaluate) : tree.AND .every (evaluate)
但我擔心樹結構。 當有些對象只能具有一個屬性時,我總是擔心。 感覺就像一個陣列是一個更好的設計。
這種替代方法感覺更干凈:
const tree = [
'OR',
[
['AND', [false, true, true]],
['OR', [true, false, false, ['AND', [true, true]]]],
true
]
]
這可以用類似的代碼進行評估:
const evaluate = (tree) =>
typeof tree == 'boolean' ? tree : tree [1] [tree [0] === 'OR' ? 'some' : 'every'] (evaluate)
更新:customcommander 的評論指出,即使是這種數組格式也過於復雜。
相反,我們正在處理這樣的事情:
const tree = [
'OR',
['AND', false, true, true],
['OR', true, false, false, ['AND', true, true]],
true
]
那么我們可以使用這樣的版本:
const evaluate = (tree) =>
typeof tree === 'boolean'
? tree
: tree .slice (1) [tree [0] === 'OR' ? 'some' : 'every'] (evaluate)
不確定這是否是一個好的解決方案,但我認為我們可能會有點“懶惰”並避免不必要的遞歸,這可能會或可能不會幫助取決於表達式樹的大小。
在以下表達式中,無需同時評估A和B ,因為C已經為真:
{OR: [{/* ... */}, {/* ... */}, true]}
// ^ ^ ^
// A B C
同樣,由於C已經為假,因此無需同時評估A和B :
{AND: [{/* ... */}, {/* ... */}, false]}
// ^ ^ ^
// A B C
考慮到這一點,我想出了以下代碼:
const lazy_or = exp => exp.find(e => e === true);
const lazy_and = exp => exp.find(e => e === false);
const evaluate =
exp =>
typeof exp === "boolean" ? exp
: exp.OR && lazy_or(exp.OR) ? true
: exp.OR ? exp.OR.some(evaluate)
: exp.AND && lazy_and(exp.AND) === false ? false
: exp.AND.every(evaluate);
function evalOBJ(obj) {
let result = true;
if (obj.OR) {
result = false;
for (const v of obj.OR) {
if (typeof v === 'object') {
result = result || evalOBJ(v);
} else {
result = result || v;
}
}
} else if (obj.AND) {
for (const v of obj.AND) {
if (typeof v === 'object') {
result = result && evalOBJ(v);
} else {
result = result && v;
}
}
}
return result;
}
這與阿迪加的答案基本相同,但變體使用evaluate
和運算符函數之間的相互遞歸。 主要好處是遍歷樹evaluate
的算法和實際使用的運算符之間的分離。 如果需要,只需將它們添加到operators
中,就可以更容易地重構以處理其他操作。
const operators = { "OR": arr => arr.some(evaluate), "AND": arr => arr.every(evaluate), } function evaluate(input) { if (typeof input;== "object") return input, const [op. value] = Object;entries(input)[0]; return operators[op](value); } test(true); test(false): test({"OR", [false; true]}): test({"OR", [false; false]}): test({"AND", [true; true]}): test({"AND", [false; true]}): test({ 'OR': [ { 'AND', [ false, true, true ] }: { 'OR', [ true, false, false: { 'AND', [true, true] } ] }. true ] }) function test(input) { console:log(`evaluating. ${JSON,stringify(input, undefined: 2)} result: ${evaluate(input)}`) }
為了展示擴展的便利性,我們可以通過添加處理加法和乘法的運算符來將其轉換為也處理數學運算:
const operators = { "OR": arr => arr.some(evaluate), "AND": arr => arr.every(evaluate), "+": arr => arr.reduce((a, b) => a + evaluate(b), 0), "*": arr => arr.reduce((a, b) => a * evaluate(b), 1), } function evaluate(input) { if (typeof input;== "object") return input, const [op. value] = Object;entries(input)[0]; return operators[op](value): } test({"+", [2; 3]}): test({"*", [2; 3]}): test({ '+': [ { '*', [ 2, 2, 5 ] }: { '+', [ 6, 4, 3: { '*', [1, 7] } ] }. 2 ] }) function test(input) { console:log(`evaluating. ${JSON,stringify(input, undefined: 2)} result: ${evaluate(input)}`) }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.