C# 评估树表达式,其中叶节点是整数集
C# Evaluate Tree expressions where leaf nodes are sets of integers
我需要在 C# 临时查询中评估树表达式的值节点是一组数字。
示例表达式
Set-A NOT SET-B AND (SET-C OR SET-D)
AND = INTERSECT
OR = UNION
NOT = EXCEPT
表达式可能会变得非常复杂 - 我的数据集来自回答了很多问题的调查的受访者。我想以特定方式回答特定问题的一组受访者作为结尾。
我已经尝试构建一个树型求值器,但虽然它在大多数情况下都有效,但在其他情况下却失败了(主要是如果我在不同的地方放置了 NOT)。
有没有人以前做过这个并且想出了一个他们想分享的优雅解决方案?最好在 C# 中 - 显然我使用 LINQ 来执行集合操作,我需要一种方法来构建和评估以不同方式组合多个集合的树。
这是我当前的代码(根据评论添加)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Z.Expressions;
using DIPEF = DataImport.EF;
namespace DataImport.Models
{
public enum OPMODEL { NULL = 0, AND = 1, OR = 2, NOT = 3, ORNOT = 4 }
public class DemographicOption
{
public long OptionId { get; set; }
public long QuestionId { get; set; }
public string QuestionText { get; set; }
public string OptionText { get; set; }
public OPMODEL Operation { get; set; }
public bool LParen { get; set; }
public bool RParen { get; set; }
public string Logic { get; set; }
public DemographicOption()
{
Operation = OPMODEL.NULL;
QuestionId = 0;
}
}
public class DemographicTree
{
public int projectId { get; set; }
public OPMODEL Operation; //root node
public long OptionId;
public long QuestionId;
public string Logic;
public string OptionText;
public DemographicTree LChild; // Complex Node
public DemographicTree RChild; // Complex Node
public Stack<OPMODEL> opStack = new Stack<OPMODEL>();
public bool Not { get; set; }
public DemographicTree()
{
Operation = OPMODEL.NULL;
LChild = null;
RChild = null;
Not = false;
}
private DemographicTree LChildTree(ref List<DemographicOption> list)
{
if (list == null || list.Count == 0)
return null;
DemographicOption o = list[0];
DemographicTree T = new DemographicTree();
T.Operation = o.Operation;
T.LChild = new DemographicTree();
T.LChild.QuestionId = o.QuestionId;
T.LChild.Logic = o.Logic;
T.LChild.OptionId = o.OptionId;
T.LChild.OptionText = o.OptionText;
list.RemoveAt(0);
if (list.Count > 0)
{
opStack.Push(list[0].Operation);
T.RChild = new DemographicTree(list);
}
return T;
}
public DemographicTree(List<DemographicOption> list)
{
if (list == null || list.Count == 0)
return;
DemographicOption o = list[0];
DemographicOption ultima = list.Last();
if (ultima.RParen == true && ultima.Operation == OPMODEL.NOT)
Not = true;
Operation = o.Operation;
if (o.RParen == true)
{
OptionId = o.OptionId;
QuestionId = o.QuestionId;
Logic = o.Logic;
OptionText = o.OptionText;
opStack.Push(o.Operation);
list.RemoveAt(0);
return;
}
if (o.Operation == OPMODEL.NULL && list.Count == 1)
{
OptionId = o.OptionId;
QuestionId = o.QuestionId;
Logic = o.Logic;
OptionText = o.OptionText;
list.RemoveAt(0);
return;
}
// Operation = o.Operation;
opStack.Push(Operation);
if (o.LParen == true)
{
LChild = LChildTree(ref list);
if (list == null || list.Count == 0)
return;
}
else
{
LChild = new DemographicTree();
LChild.OptionId = o.OptionId;
LChild.QuestionId = o.QuestionId;
LChild.Logic = o.Logic;
LChild.OptionText = o.OptionText;
list.RemoveAt(0);
}
if (list.Count == 1 )
{
if (o.RParen == true)
LChild.Operation = o.Operation;
o = list[0];
RChild = new DemographicTree();
RChild.OptionId = o.OptionId;
RChild.QuestionId = o.QuestionId;
RChild.Logic = o.Logic;
RChild.OptionText = o.OptionText;
// Operation = opStack.Pop();
}
if (list.Count > 1)
{
Operation = opStack.Pop();
RChild = new DemographicTree(list);
}
}
public static bool EvaluateLogicalExpression(string logicalExpression)
{
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("", typeof(bool));
table.Columns[0].Expression = logicalExpression;
System.Data.DataRow r = table.NewRow();
table.Rows.Add(r);
bool result = (Boolean)r[0];
return result;
}
public long findFirstOptionId(DemographicTree dt)
{
if (dt.OptionId > 0)
return dt.OptionId;
if (dt.RChild != null)
return findFirstOptionId(dt.RChild);
if (dt.LChild != null)
return findFirstOptionId(dt.LChild);
return 0;
}
public String toString(DemographicTree dt)
{
string s = "";
if (dt == null) return s;
using (var entities = new DIPEF.DataImportDB())
{
if (dt.Operation == OPMODEL.NULL && dt.QuestionId == 0)
{
if (dt.OptionId > 0)
s = entities.Options.FirstOrDefault(O => O.OptionId == dt.OptionId).Name;
return s;
}
else if (dt.Operation == OPMODEL.NULL && dt.QuestionId > 0 && String.IsNullOrEmpty(dt.Logic))
{
s = entities.Questions.FirstOrDefault(Q => Q.QuestionId == dt.QuestionId).Name;
return s;
}
else if (dt.QuestionId > 0 && !String.IsNullOrEmpty(dt.Logic))
{
var q = entities.Questions.FirstOrDefault(Q => Q.QuestionId == dt.QuestionId);
s += string.Format(" {0} {1}", q.Name, dt.Logic);
if (dt.Operation == OPMODEL.NULL)
return s;
}
switch (dt.Operation)
{
case OPMODEL.AND:
{
s += " " + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.OR:
{
s += " " + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.NOT:
{
s += " !" + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.ORNOT:
{
s += " OR !" + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
}
}
return s;
}
public List<long> Evaluate(DemographicTree dt, bool NOT)
{
var respondents = Evaluate(dt);
if (NOT == true)
{
var optionId = findFirstOptionId(dt);
using (var entities = new DIPEF.DataImportDB())
{
var option = entities.Options.FirstOrDefault(O => O.OptionId == optionId);
if (option != null)
{
var resp = entities.Responses.Where(R => R.QuestionId == option.QuestionId).Select(r => r.RespondentId).Distinct().ToList();
respondents = resp.Except(respondents).ToList();
}
}
}
return respondents;
}
public List<long> Evaluate(DemographicTree dt)
{
Console.WriteLine("{0}", dt.toString(dt));
using (var entities = new DIPEF.DataImportDB())
{
if (dt.Operation == OPMODEL.NULL && dt.QuestionId == 0)
{
var respondents = entities.Responses.Where(R=>R.OptionId == dt.OptionId).Select(r => r.RespondentId).Distinct().ToList();
return respondents;
}
else if (dt.Operation == OPMODEL.NULL && dt.QuestionId > 0 && dt.OptionId==0 && String.IsNullOrEmpty(dt.Logic))
{
var respondents = entities.Responses.Where(R => R.QuestionId == dt.QuestionId).Select(r => r.RespondentId).Distinct().ToList();
return respondents;
}
else if ( dt.QuestionId > 0 && !String.IsNullOrEmpty(dt.Logic))
{
var respondents = new List<long>();
var responses = entities.Responses.Where(R => R.QuestionId == dt.QuestionId).ToList();
if (dt.Logic.Trim().ToUpper() == "N/A" || dt.Logic.ToLower().Trim() == "is null")
{
int projectId = responses.First().ProjectId;
List<long> allRespondents = entities.Respondents.Where(R => R.ProjectId == projectId).Select(A => A.RespondentId).ToList();
List<long> qRespondents = responses.Select(B => B.RespondentId).ToList();
respondents = allRespondents.Except(qRespondents).ToList();
}
else foreach(DIPEF.Response r in responses)
{
var o = entities.Options.FirstOrDefault(O => O.OptionId == r.OptionId);
string expression = string.Format("{0} {1}", o.Value, dt.Logic);
if (Regex.IsMatch(dt.Logic, @"^[a-zA-Z]+$"))
{
if (o.Name.ToLower().Contains(dt.Logic.ToLower()))
{
respondents.Add(r.RespondentId);
}
}
else
{
if (EvaluateLogicalExpression(expression) == true)
if (!respondents.Contains(r.RespondentId))
respondents.Add(r.RespondentId);
}
}
if (dt.Operation == OPMODEL.NULL)
return respondents;
}
Console.WriteLine(String.Format("{0} {1} {2}", dt.LChild == null ? "null":dt.LChild.toString(dt.LChild), dt.Operation, dt.RChild == null ? "null": dt.RChild.toString(dt.RChild)));
switch (dt.Operation)
{
case OPMODEL.AND:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
lResp = lResp.Intersect(Evaluate(dt.RChild)).ToList();
return lResp.Distinct().ToList();
}
case OPMODEL.OR:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Union(rResp).ToList();
return resp;
}
case OPMODEL.NOT:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Except(rResp).ToList();
return resp;
}
case OPMODEL.ORNOT:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Except(rResp).ToList();
return resp;
}
}
return new List<long>();
}
}
}
}
好的 - 我的原始代码很乱,我强迫自己编写了一个更通用的集合表达式求值器。我仍然输入了一个 'Expression' 对象数组,但与我最初的尝试不太具体。这是结果及其使用方式:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace SetExpressions
{
public class Expression
{
public List<long> Value { get; set; }
public char Op { get;set; }
public bool lParen { get; set; }
public bool rParen { get; set; }
public Expression ( List<long> value, char op, bool lp, bool rp)
{
Op = op;
Value = value;
lParen = lp;
rParen = rp;
}
}
class SetExpressionEvaluator
{
Stack<List<long>> valueStack = new Stack<List<long>>();
Stack<char> operatorStack = new Stack<char>();
private void EvaluatePartial()
{
char op = operatorStack.Pop();
while (op != '(')
{
var right = valueStack.Pop();
var left = valueStack.Pop();
var newval = Apply(op, left, right);
valueStack.Push(newval);
op = operatorStack.Pop();
}
}
public List<long> Apply(char op, List<long> left, List<long> right)
{
List<long> res = new List<long>();
switch (op)
{
case '&':
res = left.Intersect(right).ToList(); break;
case '|':
res = left.Union(right).ToList(); break;
case '!':
res = left.Except(right).ToList(); break;
}
return res;
}
public List<long> Evaluate(Expression [] expressions)
{
if (expressions.Length == 0)
{
return new List<long>();
}
operatorStack.Clear();
valueStack.Clear();
foreach (Expression expression in expressions)
{
valueStack.Push(expression.Value);
if (expression.lParen)
{
operatorStack.Push('(');
}
if (expression.Op != '[=10=]')
operatorStack.Push(expression.Op);
if (expression.rParen)
{
EvaluatePartial();
}
}
while (operatorStack.Count > 0)
{
var right = valueStack.Pop();
var left = valueStack.Pop();
var newval = Apply(operatorStack.Pop(), left, right);
valueStack.Push(newval);
}
return valueStack.Pop();
}
}
}
测试代码:
using SetExpressions;
using System;
using System.Collections.Generic;
namespace ExpressionEvaluator
{
class Program
{
static void Main(string[] args)
{
SetExpressionEvaluator x = new SetExpressionEvaluator();
var A = new List<long> { 1, 2, 3 };
var B = new List<long> { 3, 4, 5 };
var C = new List<long> { 5, 6, 7 };
// A & B
List<Expression> list = new List<Expression>();
list.Add(new Expression(A, '&', false, false));
list.Add(new Expression(B, '[=11=]', false, false));
var X = x.Evaluate(list.ToArray());
Console.WriteLine(String.Join(',', X));
list = new List<Expression>();
list.Add(new Expression(A, '&', false, false));
list.Add(new Expression(B, '|', true, false));
list.Add(new Expression(C, '[=11=]', false, true));
X = x.Evaluate(list.ToArray());
Console.WriteLine(String.Join(',', X));
}
}
}
我需要在 C# 临时查询中评估树表达式的值节点是一组数字。
示例表达式 Set-A NOT SET-B AND (SET-C OR SET-D)
AND = INTERSECT
OR = UNION
NOT = EXCEPT
表达式可能会变得非常复杂 - 我的数据集来自回答了很多问题的调查的受访者。我想以特定方式回答特定问题的一组受访者作为结尾。
我已经尝试构建一个树型求值器,但虽然它在大多数情况下都有效,但在其他情况下却失败了(主要是如果我在不同的地方放置了 NOT)。
有没有人以前做过这个并且想出了一个他们想分享的优雅解决方案?最好在 C# 中 - 显然我使用 LINQ 来执行集合操作,我需要一种方法来构建和评估以不同方式组合多个集合的树。
这是我当前的代码(根据评论添加)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Z.Expressions;
using DIPEF = DataImport.EF;
namespace DataImport.Models
{
public enum OPMODEL { NULL = 0, AND = 1, OR = 2, NOT = 3, ORNOT = 4 }
public class DemographicOption
{
public long OptionId { get; set; }
public long QuestionId { get; set; }
public string QuestionText { get; set; }
public string OptionText { get; set; }
public OPMODEL Operation { get; set; }
public bool LParen { get; set; }
public bool RParen { get; set; }
public string Logic { get; set; }
public DemographicOption()
{
Operation = OPMODEL.NULL;
QuestionId = 0;
}
}
public class DemographicTree
{
public int projectId { get; set; }
public OPMODEL Operation; //root node
public long OptionId;
public long QuestionId;
public string Logic;
public string OptionText;
public DemographicTree LChild; // Complex Node
public DemographicTree RChild; // Complex Node
public Stack<OPMODEL> opStack = new Stack<OPMODEL>();
public bool Not { get; set; }
public DemographicTree()
{
Operation = OPMODEL.NULL;
LChild = null;
RChild = null;
Not = false;
}
private DemographicTree LChildTree(ref List<DemographicOption> list)
{
if (list == null || list.Count == 0)
return null;
DemographicOption o = list[0];
DemographicTree T = new DemographicTree();
T.Operation = o.Operation;
T.LChild = new DemographicTree();
T.LChild.QuestionId = o.QuestionId;
T.LChild.Logic = o.Logic;
T.LChild.OptionId = o.OptionId;
T.LChild.OptionText = o.OptionText;
list.RemoveAt(0);
if (list.Count > 0)
{
opStack.Push(list[0].Operation);
T.RChild = new DemographicTree(list);
}
return T;
}
public DemographicTree(List<DemographicOption> list)
{
if (list == null || list.Count == 0)
return;
DemographicOption o = list[0];
DemographicOption ultima = list.Last();
if (ultima.RParen == true && ultima.Operation == OPMODEL.NOT)
Not = true;
Operation = o.Operation;
if (o.RParen == true)
{
OptionId = o.OptionId;
QuestionId = o.QuestionId;
Logic = o.Logic;
OptionText = o.OptionText;
opStack.Push(o.Operation);
list.RemoveAt(0);
return;
}
if (o.Operation == OPMODEL.NULL && list.Count == 1)
{
OptionId = o.OptionId;
QuestionId = o.QuestionId;
Logic = o.Logic;
OptionText = o.OptionText;
list.RemoveAt(0);
return;
}
// Operation = o.Operation;
opStack.Push(Operation);
if (o.LParen == true)
{
LChild = LChildTree(ref list);
if (list == null || list.Count == 0)
return;
}
else
{
LChild = new DemographicTree();
LChild.OptionId = o.OptionId;
LChild.QuestionId = o.QuestionId;
LChild.Logic = o.Logic;
LChild.OptionText = o.OptionText;
list.RemoveAt(0);
}
if (list.Count == 1 )
{
if (o.RParen == true)
LChild.Operation = o.Operation;
o = list[0];
RChild = new DemographicTree();
RChild.OptionId = o.OptionId;
RChild.QuestionId = o.QuestionId;
RChild.Logic = o.Logic;
RChild.OptionText = o.OptionText;
// Operation = opStack.Pop();
}
if (list.Count > 1)
{
Operation = opStack.Pop();
RChild = new DemographicTree(list);
}
}
public static bool EvaluateLogicalExpression(string logicalExpression)
{
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("", typeof(bool));
table.Columns[0].Expression = logicalExpression;
System.Data.DataRow r = table.NewRow();
table.Rows.Add(r);
bool result = (Boolean)r[0];
return result;
}
public long findFirstOptionId(DemographicTree dt)
{
if (dt.OptionId > 0)
return dt.OptionId;
if (dt.RChild != null)
return findFirstOptionId(dt.RChild);
if (dt.LChild != null)
return findFirstOptionId(dt.LChild);
return 0;
}
public String toString(DemographicTree dt)
{
string s = "";
if (dt == null) return s;
using (var entities = new DIPEF.DataImportDB())
{
if (dt.Operation == OPMODEL.NULL && dt.QuestionId == 0)
{
if (dt.OptionId > 0)
s = entities.Options.FirstOrDefault(O => O.OptionId == dt.OptionId).Name;
return s;
}
else if (dt.Operation == OPMODEL.NULL && dt.QuestionId > 0 && String.IsNullOrEmpty(dt.Logic))
{
s = entities.Questions.FirstOrDefault(Q => Q.QuestionId == dt.QuestionId).Name;
return s;
}
else if (dt.QuestionId > 0 && !String.IsNullOrEmpty(dt.Logic))
{
var q = entities.Questions.FirstOrDefault(Q => Q.QuestionId == dt.QuestionId);
s += string.Format(" {0} {1}", q.Name, dt.Logic);
if (dt.Operation == OPMODEL.NULL)
return s;
}
switch (dt.Operation)
{
case OPMODEL.AND:
{
s += " " + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.OR:
{
s += " " + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.NOT:
{
s += " !" + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
case OPMODEL.ORNOT:
{
s += " OR !" + toString(dt.LChild);
if (dt.RChild == null)
return s;
s += " " + toString(dt.RChild);
return s;
}
}
}
return s;
}
public List<long> Evaluate(DemographicTree dt, bool NOT)
{
var respondents = Evaluate(dt);
if (NOT == true)
{
var optionId = findFirstOptionId(dt);
using (var entities = new DIPEF.DataImportDB())
{
var option = entities.Options.FirstOrDefault(O => O.OptionId == optionId);
if (option != null)
{
var resp = entities.Responses.Where(R => R.QuestionId == option.QuestionId).Select(r => r.RespondentId).Distinct().ToList();
respondents = resp.Except(respondents).ToList();
}
}
}
return respondents;
}
public List<long> Evaluate(DemographicTree dt)
{
Console.WriteLine("{0}", dt.toString(dt));
using (var entities = new DIPEF.DataImportDB())
{
if (dt.Operation == OPMODEL.NULL && dt.QuestionId == 0)
{
var respondents = entities.Responses.Where(R=>R.OptionId == dt.OptionId).Select(r => r.RespondentId).Distinct().ToList();
return respondents;
}
else if (dt.Operation == OPMODEL.NULL && dt.QuestionId > 0 && dt.OptionId==0 && String.IsNullOrEmpty(dt.Logic))
{
var respondents = entities.Responses.Where(R => R.QuestionId == dt.QuestionId).Select(r => r.RespondentId).Distinct().ToList();
return respondents;
}
else if ( dt.QuestionId > 0 && !String.IsNullOrEmpty(dt.Logic))
{
var respondents = new List<long>();
var responses = entities.Responses.Where(R => R.QuestionId == dt.QuestionId).ToList();
if (dt.Logic.Trim().ToUpper() == "N/A" || dt.Logic.ToLower().Trim() == "is null")
{
int projectId = responses.First().ProjectId;
List<long> allRespondents = entities.Respondents.Where(R => R.ProjectId == projectId).Select(A => A.RespondentId).ToList();
List<long> qRespondents = responses.Select(B => B.RespondentId).ToList();
respondents = allRespondents.Except(qRespondents).ToList();
}
else foreach(DIPEF.Response r in responses)
{
var o = entities.Options.FirstOrDefault(O => O.OptionId == r.OptionId);
string expression = string.Format("{0} {1}", o.Value, dt.Logic);
if (Regex.IsMatch(dt.Logic, @"^[a-zA-Z]+$"))
{
if (o.Name.ToLower().Contains(dt.Logic.ToLower()))
{
respondents.Add(r.RespondentId);
}
}
else
{
if (EvaluateLogicalExpression(expression) == true)
if (!respondents.Contains(r.RespondentId))
respondents.Add(r.RespondentId);
}
}
if (dt.Operation == OPMODEL.NULL)
return respondents;
}
Console.WriteLine(String.Format("{0} {1} {2}", dt.LChild == null ? "null":dt.LChild.toString(dt.LChild), dt.Operation, dt.RChild == null ? "null": dt.RChild.toString(dt.RChild)));
switch (dt.Operation)
{
case OPMODEL.AND:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
lResp = lResp.Intersect(Evaluate(dt.RChild)).ToList();
return lResp.Distinct().ToList();
}
case OPMODEL.OR:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Union(rResp).ToList();
return resp;
}
case OPMODEL.NOT:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Except(rResp).ToList();
return resp;
}
case OPMODEL.ORNOT:
{
var lResp = Evaluate(dt.LChild);
if (dt.RChild == null)
return lResp;
var rResp = Evaluate(dt.RChild);
var resp = lResp.Except(rResp).ToList();
return resp;
}
}
return new List<long>();
}
}
}
}
好的 - 我的原始代码很乱,我强迫自己编写了一个更通用的集合表达式求值器。我仍然输入了一个 'Expression' 对象数组,但与我最初的尝试不太具体。这是结果及其使用方式:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace SetExpressions
{
public class Expression
{
public List<long> Value { get; set; }
public char Op { get;set; }
public bool lParen { get; set; }
public bool rParen { get; set; }
public Expression ( List<long> value, char op, bool lp, bool rp)
{
Op = op;
Value = value;
lParen = lp;
rParen = rp;
}
}
class SetExpressionEvaluator
{
Stack<List<long>> valueStack = new Stack<List<long>>();
Stack<char> operatorStack = new Stack<char>();
private void EvaluatePartial()
{
char op = operatorStack.Pop();
while (op != '(')
{
var right = valueStack.Pop();
var left = valueStack.Pop();
var newval = Apply(op, left, right);
valueStack.Push(newval);
op = operatorStack.Pop();
}
}
public List<long> Apply(char op, List<long> left, List<long> right)
{
List<long> res = new List<long>();
switch (op)
{
case '&':
res = left.Intersect(right).ToList(); break;
case '|':
res = left.Union(right).ToList(); break;
case '!':
res = left.Except(right).ToList(); break;
}
return res;
}
public List<long> Evaluate(Expression [] expressions)
{
if (expressions.Length == 0)
{
return new List<long>();
}
operatorStack.Clear();
valueStack.Clear();
foreach (Expression expression in expressions)
{
valueStack.Push(expression.Value);
if (expression.lParen)
{
operatorStack.Push('(');
}
if (expression.Op != '[=10=]')
operatorStack.Push(expression.Op);
if (expression.rParen)
{
EvaluatePartial();
}
}
while (operatorStack.Count > 0)
{
var right = valueStack.Pop();
var left = valueStack.Pop();
var newval = Apply(operatorStack.Pop(), left, right);
valueStack.Push(newval);
}
return valueStack.Pop();
}
}
}
测试代码:
using SetExpressions;
using System;
using System.Collections.Generic;
namespace ExpressionEvaluator
{
class Program
{
static void Main(string[] args)
{
SetExpressionEvaluator x = new SetExpressionEvaluator();
var A = new List<long> { 1, 2, 3 };
var B = new List<long> { 3, 4, 5 };
var C = new List<long> { 5, 6, 7 };
// A & B
List<Expression> list = new List<Expression>();
list.Add(new Expression(A, '&', false, false));
list.Add(new Expression(B, '[=11=]', false, false));
var X = x.Evaluate(list.ToArray());
Console.WriteLine(String.Join(',', X));
list = new List<Expression>();
list.Add(new Expression(A, '&', false, false));
list.Add(new Expression(B, '|', true, false));
list.Add(new Expression(C, '[=11=]', false, true));
X = x.Evaluate(list.ToArray());
Console.WriteLine(String.Join(',', X));
}
}
}