【问题标题】:How to filter nested JSON and preserve branch hierarchy for matches?如何过滤嵌套的 JSON 并保留匹配的分支层次结构?
【发布时间】:2015-06-16 04:42:46
【问题描述】:

这个很棘手...关于如何遍历树有很多问题和答案,但我无法根据我的特殊情况调整任何建议的解决方案。我的问题很接近Python: How can I filter a n-nested dict of dicts by leaf value?

我的 JSON 数据具有特殊的嵌套结构(子术语、同义词、名称、id),可以是任意深度。

tree=[{'id': 20, 'name': 'education', 'subterms': [
               {'id': 21, 'name': 'schools', 'synonyms': []},
               {'id': 22, 'name': 'schoolbooks', 'synonyms': ['literature']},
               {'id': 23, 'name': 'higher education', 'synonyms': ['university']},
               {'id': 25, 'name': 'conference', 'synonyms': ['lecture']}]},
 {'id': 26, 'name': 'health', 'subterms': [
               {'id': 27, 'name': 'health issues', 'synonyms': []},
               {'id': 28, 'name': 'nutrition', 'synonyms': []},
               {'id': 29, 'name': 'medicine', 'synonyms': []}]},
 {'id': 1, 'name': 'business', 'subterms': [{'id': 2,
                'name': 'industry',
                'subterms': [{'id': 21, 'name': 'service', 'synonyms': []},
                             {'id': 21, 'name': 'agriculture', 'synonyms': []}],
                'synonyms': []},
               {'id': 3, 'name': 'professions', 'synonyms': ['jobs']}]}]

我的目标是通过匹配“名称”和“同义词”来过滤这棵树。必须保留匹配项的分支层次结构:级别 3 上的匹配子项意味着级别 1 和 2 上的父项也被保留(但不保留子项)。

例如,使用filterterms=['literature', 'agriculture'] 应该会产生以下过滤树:

[{'id': 20, 'name': 'education', 'subterms': [
               {'id': 22,'name': 'schoolbooks', 'synonyms': ['literature']}]},
 {'id': 1, 'name': 'business', 'subterms': [{'id': 2, 'name': 'industry',
                'subterms': [{'id': 21, 'name': 'agriculture', 'synonyms': []}],
                'synonyms': []}]}]

到目前为止,我在 n 层上遍历树并保留匹配项的分支层次结构的所有尝试都失败了...关于如何解决此任务的任何帮助?

【问题讨论】:

    标签: python json dictionary tree hierarchy


    【解决方案1】:

    我认为这可以满足您的需求。

    tree=[{'id': 20, 'name': 'education', 'subterms': [
                   {'id': 21, 'name': 'schools', 'synonyms': []},
                   {'id': 22, 'name': 'schoolbooks', 'synonyms': ['literature']},
                   {'id': 23, 'name': 'higher education', 'synonyms': ['university']},
                   {'id': 25, 'name': 'conference', 'synonyms': ['lecture']}]},
     {'id': 26, 'name': 'health', 'subterms': [
                   {'id': 27, 'name': 'health issues', 'synonyms': []},
                   {'id': 28, 'name': 'nutrition', 'synonyms': []},
                   {'id': 29, 'name': 'medicine', 'synonyms': []}]},
     {'id': 1, 'name': 'business', 'subterms': [{'id': 2,
                    'name': 'industry',
                    'subterms': [{'id': 21, 'name': 'service', 'synonyms': []},
                                 {'id': 21, 'name': 'agriculture', 'synonyms': []}],
                    'synonyms': []},
                   {'id': 3, 'name': 'professions', 'synonyms': ['jobs']}]}]
    
    def filter_by_name(node, names):
        if isinstance(node, list):
            return filter(None, (filter_by_name(x, names) for x in node if x))
        subterms = filter(None, filter_by_name(node.get('subterms',[]), names))
        if set([node['name']]+node.get('synonyms',[])).intersection(names):
            return dict(node, subterms=subterms)
        if subterms:
            return dict(node, subterms=subterms)
        return None
    
    
    from pprint import pprint
    pprint(filter_by_name(tree, ['business']))
    pprint(filter_by_name(tree, ['literature']))
    pprint(filter_by_name(tree, ['literature', 'agriculture']))
    

    结果:

    [{'id': 1, 'name': 'business', 'subterms': []}]
    [{'id': 20,
      'name': 'education',
      'subterms': [{'id': 22,
                    'name': 'schoolbooks',
                    'subterms': [],
                    'synonyms': ['literature']}]}]
    [{'id': 20,
      'name': 'education',
      'subterms': [{'id': 22,
                    'name': 'schoolbooks',
                    'subterms': [],
                    'synonyms': ['literature']}]},
     {'id': 1,
      'name': 'business',
      'subterms': [{'id': 2,
                    'name': 'industry',
                    'subterms': [{'id': 21,
                                  'name': 'agriculture',
                                  'subterms': [],
                                  'synonyms': []}],
                    'synonyms': []}]}]
    

    【讨论】:

    • 很棒的代码。在这个小功能中可以学到很多东西。但是有一个小故障:当您提交父术语(例如“教育”)时,它还会选择所有子术语。如何避免这种情况?基本上它应该只选择层次结构中的所有术语,直到提交的术语,但不能超过。
    • 我已经编辑了我的答案。也许这个版本可以满足您的需求。
    猜你喜欢
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 2022-08-03
    • 1970-01-01
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多