【问题标题】:reducing nested dictionaries defined by a boolean operator减少由布尔运算符定义的嵌套字典
【发布时间】:2019-08-11 23:46:17
【问题描述】:

假设我有一个如下所示的有效负载:

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]

此时我可以使用字符串 ANDOR 作为布尔运算符,感觉好像它们分别映射到 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
        )

这适用于单个布尔运算符和包含值的列表列表。但是,我在递归方面遇到了麻烦。有什么建议么?我是否过于复杂了?想把它变成一个整洁的库以供使用。

非常感谢您提供任何见解。

2019 年 8 月 12 日更新

@Ajax1234 的解决方案效果很好,直到我遇到给定布尔运算符有 > 2 个块的情况,例如

payload = {'OR': [
              {'AND': [
                        [
                             ('5657',),
                             ('5698',)               
                        ]
                   ]
              },
              {'AND': [
                        [
                             ('6101',),
                             ('5420',),
                             ('5334',),
                             ('5439',)
                        ]
                   ]
              },
              {'AND': [
                        [
                             ('5802',),
                             ('6005',),     
                             ('6675',),
                             ('5878',)
                        ]
                   ]
              },
              {'AND': [
                        [
                             ('6265',),
                             ('6157',),
                             ('6238',),
                             ('6189',),
                             ('6191',)
                        ]
                   ]
              }
        ]
    }

更新要求:理想情况下可以在上述有效负载上工作。

2019 年 8 月 13 日更新

仍然遇到边缘情况,例如以下载荷:

payload = {
    'AND': [
        {
            'OR': [
                [('6101',)],
                [('6265',)]
            ]
        }
    ]
}

在这种情况下,我的输出是单值集:{'OR'},尽管我希望是 {('6101',),('6265',)}。感谢您到目前为止@ajax1234 的帮助,有什么建议吗?

【问题讨论】:

  • 你需要bool_operator做什么?
  • @Samha', bool_operator 用于从set 实例中获取方法;需要允许ANDOR 之类的字符串,但需要来自set 的方法。

标签: python algorithm recursion reduce


【解决方案1】:

您可以将functools.reducegetattr 一起使用:

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',)}

【讨论】:

  • Huzzah,万岁,太棒了。奇迹般有效。非常感谢!
  • 工作就像一个魅力,@ajax1234,直到我遇到了每个操作员有 > 2 个块的情况。我花了一些时间查看您的答案以理解它,我认为我现在这样做了。但是考虑到第一个解决方案的优雅程度,我很好奇您如何更改它以适应更新的要求?谢谢。
  • @ghukill 请看我最近的编辑。 functools.reduce 在这种情况下效果很好。
  • 当然!非常感谢您对此@ajax1234 的想法。
  • 再次返回@ajax1234;遇到另一个极端情况。了解您是否刚刚完成了这个小麻烦,否则,请继续感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2017-08-31
  • 2020-06-07
  • 1970-01-01
  • 2014-10-28
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
相关资源
最近更新 更多