如何将pyparsing解析的布尔表达式转换为Python可执行的集合运算逻辑?
实现方案
核心逻辑:你已经完成了表达式解析生成布尔树的步骤,只需要给AND_、OR_两个类实现两个核心能力即可满足需求:
- 实现
__contains__魔术方法,直接支持value in 表达式的判断语法 - 实现
eval方法,直接遍历子节点计算出整个表达式的结果集
代码实现
from typing import List, Dict, Set, Union # 布尔表达式节点基类,存储全局数据 class BoolExpr: # 存储键对应的字符串集合,提前转集合提升查找效率 data: Dict[str, Set[str]] = None @classmethod def set_data(cls, input_data: Dict[str, List[str]]): cls.data = {k: set(v) for k, v in input_data.items()} # 交集节点类 class AND_(BoolExpr): def __init__(self, children: List[Union[str, BoolExpr]]): self.children = children def __contains__(self, value: str) -> bool: # 交集要求所有子条件都满足 for child in self.children: if isinstance(child, str): if value not in self.data[child]: return False else: if value not in child: return False return True def eval(self) -> Set[str]: # 计算所有子节点的交集 result = None for child in self.children: current = self.data[child] if isinstance(child, str) else child.eval() result = current.copy() if result is None else result & current return result # 并集节点类 class OR_(BoolExpr): def __init__(self, children: List[Union[str, BoolExpr]]): self.children = children def __contains__(self, value: str) -> bool: # 并集要求任意一个子条件满足即可 for child in self.children: if isinstance(child, str): if value in self.data[child]: return True else: if value in child: return True return False def eval(self) -> Set[str]: # 计算所有子节点的并集 result = set() for child in self.children: current = self.data[child] if isinstance(child, str) else child.eval() result |= current return result
使用示例
# 加载你的测试数据 test_data = {'A': ['Hi', 'No', 'Yes'], 'B': ['Why', 'No', 'Okay'], 'C': ['Okay']} BoolExpr.set_data(test_data) # 你通过pyparsing解析生成的布尔树,对应表达式 (A and B) or C parsed_expr = OR_([ AND_(['A', 'B']), 'C' ]) # 需求1:单个值判断,完全符合你要的 if value in expr 语法 print("No" in parsed_expr) # 输出 True print("Hi" in parsed_expr) # 输出 False # 手动遍历所有值收集结果的写法 all_values = set() for lst in test_data.values(): all_values.update(lst) output = [] for val in all_values: if val in parsed_expr: output.append(val) print(output) # 输出 ['No', 'Okay'](集合顺序不固定,可自行排序) # 需求2:直接获取整个表达式的结果,无需手动遍历 result = parsed_expr.eval() print(list(result)) # 输出 ['No', 'Okay']
补充说明
- 提前把列表转成集合是为了把
in操作的时间复杂度从O(n)降到O(1),数据量大的时候性能提升明显 - 你只需要给pyparsing的解析结果加一层递归转换逻辑,把解析到的节点转成对应
AND_/OR_的实例即可,叶子节点直接存字典的键字符串 - 如果后续需要支持
not逻辑,新增一个NOT_类,实现对应取反的__contains__和eval方法即可
内容的提问来源于stack exchange,提问作者mimookies
相关产品推荐
相关产品推荐

