假设我有一个如下所示的有效负载:
payload = {
"OR": [
{
"AND" : [[1,2,3],[3,4]]
}, # ([1,2,3] AND [3,4]) --> [3]
{
"OR" : [
{
"AND" : [
{
"OR" : [[10,11],[12,13]]
}, # ([10,11] OR [12,13]) ---> [10,11,12,13]
{
"AND": [[11,13]]
} # ([11,13]) ---> [11,13]
]
}, # ([10,11,12,13] AND [11,13]) ---> [11,13]
{
"AND" : [[14,15],[15]]
} # ([14,15] AND [15]) ---> [15]
]
} # ([11,13] OR [15]) ---> [11,13,15]
]
} # ([3] OR [11,13,15]) ---> [3,11,13,15]
这时我可以将字符串AND
和OR
用作布尔运算符,感觉好像它们分别映射到set.intersection()
和set.union()
。
我在嵌套的bool_operator
字典中发表了评论:[...]
块基于运算符如何减少每个“块”。
鉴于所有这些,我想将此有效负载减少到以下水平:
[3,11,13,15]
我理解这需要递归,并为此创建了一个函数,该函数在给定纯文本布尔运算符的情况下减少了列表列表:
from functools import reduce
def reduce_block(bool_operator, block):
bool_operator_set_hash = {
'AND':'intersection',
'OR':'union'
}
return reduce(
lambda x,y: getattr(set(x),bool_operator_set_hash.get(bool_operator.upper()))(set(y)),
block
)
这对于单个布尔运算符和包含值的列表列表非常有效。但是,我在递归方面遇到了麻烦。有什么建议么?我使这个复杂化了吗?希望将其变成一个整齐的库以供使用。
在此先感谢您的见解。
更新8/12/2019
@ Ajax1234的解决方案效果很好,直到遇到一种情况,对于给定的布尔运算符,例如有两个以上的块,
payload = {'OR': [
{'AND': [
[
('5657',),
('5698',)
]
]
},
{'AND': [
[
('6101',),
('5420',),
('5334',),
('5439',)
]
]
},
{'AND': [
[
('5802',),
('6005',),
('6675',),
('5878',)
]
]
},
{'AND': [
[
('6265',),
('6157',),
('6238',),
('6189',),
('6191',)
]
]
}
]
}
要更新要求:理想情况下, 也可以在上述有效负载上工作。
更新8/13/2019
仍然遇到极端情况,例如以下有效载荷:
payload = {
'AND': [
{
'OR': [
[('6101',)],
[('6265',)]
]
}
]
}
在这种情况下,我的输出是单值集:{'OR'}
,尽管我希望有{('6101',),('6265',)}
。到目前为止,感谢您的帮助@ ajax1234,有什么建议吗?
答案 0 :(得分:1)
您可以将functools.reduce
与getattr
一起使用:
from functools import reduce
def _eval(_load):
[[op, _vals]] = _load.items()
if len(_vals) == 1:
return set(_vals[0]) if not isinstance(_vals[0], dict) else _eval(_vals[0])
return reduce(lambda l, r:getattr(_eval(l) if isinstance(l, dict) else set(l), f'__{op.lower()}__')(_eval(r) if isinstance(r, dict) else set(r)), _vals)
print(_eval(payload))
输出:
{11, 3, 13, 15}
print(_eval(new_payload))
输出:
{('5878',), ('6265',), ('5698',), ('6189',), ('5334',), ('5439',), ('6238',), ('5420',), ('5802',), ('6157',), ('6101',), ('6191',), ('6005',), ('6675',), ('5657',)}
print(_eval(_new_payload))
输出:
{('6265',), ('6101',)}