Liste der Pfade zum geschachtelten Wörterbuch

  • In Anbetracht einer Liste verschachtelter Menüelemente

     items = [
        '3D/Axis',
        '3D/CameraTracker',
    
        'Color/Invert',
        'Color/Log2Lin',
    
        'Color/Math/Add',
        'Color/Math/Multiply',
    
        'Other/Group',
        'Other/NoOp',
    
        'Views/JoinViews',
        'Views/ShuffleViews',
    
        'Views/Stereo/Anaglyph',
        'Views/Stereo/ReConverge',
    ]
     

    .. und a Dummy-Funktion, die von jedem Element ausgelöst werden soll:

     def msg(path):
        """Dummy function used in menu
        """
        return path.lower()
     

    Erstellen Sie programmatisch eine hierarchische Sammlung von Wörterbüchern, die dem entspricht Manuelle Eingabe dieses Befehls:

     menu = {
        '3D': {'Axis':                     lambda: msg('3D/Axis'),
               'CameraTracker':            lambda: msg("3D/CameraTracker")},
    
        'Color': {'Invert':                lambda: msg('Color/Invert'),
                  'Log2Lin':               lambda: msg('Color/Log2Lin'),
    
                  'Math': {'Add':          lambda: msg('Color/Add'),
                           'Multiply':     lambda: msg('Color/Multiply')}},
    
        'Other': {'Group':                 lambda: msg('Other/Group'),
                  'NoOp':                  lambda: msg('Other/NoOp')},
    
        'Views': {'JoinViews':             lambda: msg('Views/JoinViews'),
                  'ShuffleViews':          lambda: msg('Views/ShuffleViews'),
                  'Stereo': {'Anaglyph':   lambda: msg('Views/Stereo/Anaglyph'),
                             'ReConverge': lambda: msg('Views/Stereo/ReConverge')}}},
     

    .. was wie folgt getestet werden kann:

     assert menu['3D']['Axis']() == '3d/axis'
    assert menu['Color']['Invert']() == 'color/invert'
    assert menu['Color']['Math']['Add']() == 'color/math/add'
    assert menu['Views']['Stereo']['Anaglyph']() == 'views/stereo/anaglyph'
     
    01 January 2012
    joev
3 answers
  • Eine einfache Rekursion erledigt die Arbeit.

     def build_nested_helper(path, text, container):
        segs = path.split('/')
        head = segs[0]
        tail = segs[1:]
        if not tail:
            container[head] = lambda: msg(text)
        else:
            if head not in container:
                container[head] = {}
            build_nested_helper('/'.join(tail), text, container[head])
    
    def build_nested(paths):
        container = {}
        for path in paths:
            build_nested_helper(path, path, container)
        return container
    
    menu = build_nested(items)
     

    Code: 159 Zeichen

     def f(p,t,c):
     s=p.split('/');a=s[0];b=s[1:]
     if b:
      if a not in c:c[a]={}
      f('/'.join(b),t,c[a])
     else:c[a]=lambda:msg(t)
    menu={}
    for i in items:f(i,i,menu)
     
    01 January 2012
    rcreswickChristoph Leiter
  • Als Ausgangspunkt kann

     def populate_dict(item, existing_dict, fullpath = None):
        if len(item) == 1:
            existing_dict[item[0]] = lambda p=item[0]: msg(fullpath + "/" + item[0])
        else:
            head, tail = item[0], item[1:]
            existing_dict.setdefault(head, {})
            populate_dict(
                tail,
                existing_dict[head],
                fullpath = "/".join([x for x in (fullpath, head) if x is not None]))
    
    menu = {}
    for i in items:
        populate_dict(i.split("/"), menu)
     

    .. die auf:

     def p(i,e,fp=""):
     if len(i)<2:e[i[0]]=lambda p=i[0]:msg(fp+"/"+i[0])
     else:p(i[1:], e.setdefault(i[0], {}),"/".join([fp, i[0]]).lstrip("/"))
    menu = {}
    for i in items:p(i.split("/"),menu)
     
    01 January 2012
    joev
  •  #!/usr/bin/env python3
    
    from itertools import groupby
    from pprint import pprint
    
    items = [
        '3D/Axis',
        '3D/CameraTracker',
    
        'Color/Invert',
        'Color/Log2Lin',
    
        'Color/Math/Add',
        'Color/Math/Multiply',
    
        'Other/Group',
        'Other/NoOp',
    
        'Views/JoinViews',
        'Views/ShuffleViews',
    
        'Views/Stereo/Anaglyph',
        'Views/Stereo/ReConverge',
    ]
    
    def fun(group, items, path):
        sep = lambda i:i.split('/', 1)
        head = [i for i in items if len(sep(i))==2]
        tail = [i for i in items if len(sep(i))==1]
        gv = groupby(sorted(head), lambda i:sep(i)[0])
        return group, dict([(i, path+i) for i in tail] + [fun(g, [sep(i)[1] for i in v], path+g+'/') for g,v in gv])
    
    menu = dict([fun('menu', items, '')])['menu']
    pprint(menu)
     

     {'3D': {'Axis': '3D/Axis', 'CameraTracker': '3D/CameraTracker'},
     'Color': {'Invert': 'Color/Invert',
               'Log2Lin': 'Color/Log2Lin',
               'Math': {'Add': 'Color/Math/Add',
                        'Multiply': 'Color/Math/Multiply'}},
     'Other': {'Group': 'Other/Group', 'NoOp': 'Other/NoOp'},
     'Views': {'JoinViews': 'Views/JoinViews',
               'ShuffleViews': 'Views/ShuffleViews',
               'Stereo': {'Anaglyph': 'Views/Stereo/Anaglyph',
                          'ReConverge': 'Views/Stereo/ReConverge'}}}
     

    fun() dauert 6 Zeilen
    Ändern Sie einfach path+i in (path+i).lower(), um zu bekommen, was Sie möchten.

    08 January 2012
    kev