Skip to content

Instantly share code, notes, and snippets.

@oldrev
Created January 10, 2018 08:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save oldrev/c8e59f3fba8f445eab59ebe580c0864b to your computer and use it in GitHub Desktop.
Save oldrev/c8e59f3fba8f445eab59ebe580c0864b to your computer and use it in GitHub Desktop.
Typescript Expression Tree to Lambda Expression
function visitAndExpression(exprNode: any): any {
const conditions = exprNode.expressions.map(function (expr: any) { return visitExpression(expr) })
return function (it: any) { return conditions.every(function (c: any) { return c(it) }) }
}
function visitOrExpression(exprNode: any): any {
const conditions = exprNode.expressions.map(function (expr: any) { return visitExpression(expr) })
return function (it: any) { return conditions.some(function (c: any) { return c(it) }) }
}
function visitNotExpression(exprNode: any): any {
return function (it: any) {
const condition = visitExpression(exprNode.subexpression)
return !condition(it)
}
}
function visitUnaryExpression(exprNode: any): any {
switch (exprNode['node']) {
case 'and': return visitAndExpression(exprNode)
case 'or': return visitOrExpression(exprNode)
case 'not': return visitNotExpression(exprNode)
default: break;
}
}
function visitBinaryExpression(exprNode: any): any {
switch (exprNode.node) {
case 'eq': return visitEqExpression(exprNode);
case 'ne': return visitNeExpression(exprNode);
default: break;
}
}
function visitExpression(exprNode: any): any {
switch (exprNode.node) {
case 'and': return visitUnaryExpression(exprNode)
case 'or': return visitUnaryExpression(exprNode)
case 'not': return visitUnaryExpression(exprNode)
case 'eq': return visitBinaryExpression(exprNode)
case 'ne': return visitBinaryExpression(exprNode)
}
}
function visitPropertyValueExpression(propertyName: string) {
return function (it: any) { return it[propertyName] }
}
function visitEqExpression(exprNode: any) {
let leftFunc = visitPropertyValueExpression(exprNode.property)
let rightValue = visitConstantExpression(exprNode.subexpression)
return function (it: any) { return leftFunc(it) == rightValue } //TODO 这里根据字符串或者数字分开处理
}
function visitNeExpression(exprNode: any) {
let leftFunc = visitPropertyValueExpression(exprNode.property)
let rightValue = visitConstantExpression(exprNode.subexpression)
return function (it: any) { return leftFunc(it) != rightValue }
}
function visitConstantExpression(exprNode: any): any {
return exprNode.value
}
function filter(source: any[], exprNode: any): any {
const expr = visitExpression(exprNode)
return source.filter(expr)
}
const targetList = [
{ name: 'Bill', age: 30, gender: 'm' },
{ name: 'Anne', age: 28, gender: 'f' },
]
//表示 !(it.name === 'Bill') && it.gender === 'm'
const yourExpr = {
node: 'and',
expressions: [
{
node: 'not',
subexpression: {
node: 'eq',
property: 'age',
subexpression: {
node: 'constant',
value: 28
}
}
},
{
node: 'eq',
property: 'gender',
subexpression: {
node: 'constant',
value: 'm'
}
}
]
}
const expr2 = {
node: 'and',
expressions: [
{
node: 'eq',
property: 'age',
subexpression: {
node: 'constant',
value: 28
}
},
{
node: 'eq',
property: 'gender',
subexpression: {
node: 'constant',
value: 'f'
}
}
]
}
const results = filter(targetList, yourExpr)
console.log(results)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment