问题描述
所以我有这个S表达式数组
const condition = [
'OR',[
'AND',['==','$State','Alabama'],'$Profession','Software development']
],'$Undefined',''],'Texas']
],[
'OR',[
'OR','Tradesperson']
]
]
]
const testCases = [
[{'State': 'Alabama','Profession': 'Software development'},true],[{'State': 'Texas'},[{'State': 'Alabama','Profession': 'Gaming'},false],[{'State': 'Utah'},[{'Profession': 'Town crier'},[{'Profession': 'Tradesperson'},[{},false]
]
for (const [index,[context,expected]] of testCases.entries()) {
console.log(
evaluate(condition as Condition,context) === expected
? `${index} ok`
: `${index} FAIL`
)
}
到目前为止,我是
function evaluate (condition: Condition,context: Context): boolean {
if (isLogicalCondition(condition)) {
const [operator,...conditions] = condition
}
if (isComparisonCondition(condition)) {
const [operator,variable,value] = condition
}
return false
}
函数,类型和变量是
type Context = {
[k: string]: string | undefined
}
enum LogicalOperator {
And = 'AND',Or = 'OR'
}
enum Comparisonoperator {
Eq = '=='
}
type Operator = LogicalOperator | Comparisonoperator
type LogicalCondition = [LogicalOperator,...Array<Condition>]
type Variable = string
type Value = string
type ComparisonCondition = [Comparisonoperator,Variable,Value]
type Condition = LogicalCondition | ComparisonCondition
function isLogicalCondition (condition: Condition): condition is LogicalCondition {
return Object.values(LogicalOperator).includes(condition[0] as LogicalOperator)
}
function isComparisonCondition (condition: Condition): condition is ComparisonCondition {
return Object.values(Comparisonoperator).includes(condition[0] as Comparisonoperator)
}
我的问题是,我该如何以一种足够抽象的方式考虑这个问题,以解决此问题,从而满足测试而又不对测试进行硬编码?我完全迷路了...
解决方法
您应该使用递归。 “或”运算符转换为some
方法调用,而“与”运算符转换为every
方法调用。
为了平等,您应该处理任何“ $”前缀,在这种情况下,您必须在上下文对象中查找值。最好不要假设第一个参数始终带有“ $” ...,因此我建议在两个参数上都使用一个映射器,每次处理潜在的“ $”。 / p>
您可以使用此功能:
function evaluate(condition,context) {
let [operator,...arguments] = condition;
if (operator === "==") {
return arguments.map(arg => arg[0] === "$" ? context[arg.slice(1)] : arg)
.reduce(Object.is);
}
if (operator === "OR") {
return arguments.some(argument => evaluate(argument,context));
}
if (operator === "AND") {
return arguments.every(argument => evaluate(argument,context));
}
throw "unknown operator " + operator;
}
运行测试用例:
function evaluate(condition,context));
}
throw "unknown operator " + operator;
}
const condition = [
'OR',[
'AND',['==','$State','Alabama'],'$Profession','Software development']
],'$Undefined',''],'Texas']
],[
'OR',[
'OR','Tradesperson']
]
]
]
const testCases = [
[{'State': 'Alabama','Profession': 'Software development'},true],[{'State': 'Texas'},[{'State': 'Alabama','Profession': 'Gaming'},false],[{'State': 'Utah'},[{'Profession': 'Town crier'},[{'Profession': 'Tradesperson'},[{},false]
]
for (const [index,[context,expected]] of testCases.entries()) {
console.log(
evaluate(condition,context) === expected
? `${index} ok`
: `${index} FAIL`
)
}