代码之家  ›  专栏  ›  技术社区  ›  significance

如何重写此函数以实现OrderedDict?

  •  12
  • significance  · 技术社区  · 14 年前

    不幸的是,由于没有对Python字典进行排序,我无法按照自己的意愿循环遍历节点。

    如何更改它,以便它输出一个有序字典,该字典反映了循环时节点的原始顺序 for .

    def simplexml_load_file(file):
        import collections
        from lxml import etree
    
        tree = etree.parse(file)
        root = tree.getroot()
    
        def xml_to_item(el):
            item = None
            if el.text:
                item = el.text
            child_dicts = collections.defaultdict(list)
            for child in el.getchildren():
                child_dicts[child.tag].append(xml_to_item(child))
            return dict(child_dicts) or item
    
        def xml_to_dict(el):
            return {el.tag: xml_to_item(el)}
    
        return xml_to_dict(root)
    
    x = simplexml_load_file('routines/test.xml')
    
    print x
    
    for y in x['root']:
        print y
    

    {'root': {
        'a': ['1'],
        'aa': [{'b': [{'c': ['2']}, '2']}],
        'aaaa': [{'bb': ['4']}],
        'aaa': ['3'],
        'aaaaa': ['5']
    }}
    
    a
    aa
    aaaa
    aaa
    aaaaa
    

    我如何实现 collections.OrderedDict 这样我就可以确定得到正确的节点顺序了?

    <root>
        <a>1</a>
        <aa>
            <b>
                <c>2</c>
            </b>
            <b>2</b>
        </aa>
        <aaa>3</aaa>
        <aaaa>
            <bb>4</bb>
        </aaaa>
        <aaaaa>5</aaaaa>
    </root>
    
    3 回复  |  直到 5 年前
        1
  •  32
  •   martineau    5 年前

    你可以用新的 OrderedDict dict 添加到标准库的 collections . 实际上你需要的是 Ordered defaultdict 有序的信息技术 如下图所示:

    有序的信息技术 ,你应该可以用雷蒙德·赫廷格的 Ordered Dictionary for Py2.4 而将ActiveState recipe作为基类。

    import collections
    
    class OrderedDefaultdict(collections.OrderedDict):
        """ A defaultdict with OrderedDict as its base class. """
    
        def __init__(self, default_factory=None, *args, **kwargs):
            if not (default_factory is None
                    or isinstance(default_factory, collections.Callable)):
                raise TypeError('first argument must be callable or None')
            super(OrderedDefaultdict, self).__init__(*args, **kwargs)
            self.default_factory = default_factory  # called by __missing__()
    
        def __missing__(self, key):
            if self.default_factory is None:
                raise KeyError(key,)
            self[key] = value = self.default_factory()
            return value
    
        def __reduce__(self):  # optional, for pickle support
            args = (self.default_factory,) if self.default_factory else tuple()
            return self.__class__, args, None, None, self.iteritems()
    
        def __repr__(self):  # optional
            return '%s(%r, %r)' % (self.__class__.__name__, self.default_factory,
                                   list(self.iteritems()))
    
    def simplexml_load_file(file):
        from lxml import etree
    
        tree = etree.parse(file)
        root = tree.getroot()
    
        def xml_to_item(el):
            item = el.text or None
            child_dicts = OrderedDefaultdict(list)
            for child in el.getchildren():
                child_dicts[child.tag].append(xml_to_item(child))
            return collections.OrderedDict(child_dicts) or item
    
        def xml_to_dict(el):
            return {el.tag: xml_to_item(el)}
    
        return xml_to_dict(root)
    
    x = simplexml_load_file('routines/test.xml')
    print(x)
    
    for y in x['root']:
        print(y)
    

    从测试XML文件生成的输出如下所示:

    {'root':
        OrderedDict(
            [('a', ['1']),
             ('aa', [OrderedDict([('b', [OrderedDict([('c', ['2'])]), '2'])])]),
             ('aaa', ['3']),
             ('aaaa', [OrderedDict([('bb', ['4'])])]),
             ('aaaaa', ['5'])
            ]
        )
    }
    
    a
    aa
    aaa
    aaaa
    aaaaa
    

    我想已经接近你想要的了。

    次要更新:

    __reduce__() 方法,该方法将允许正确地pickle和unpickle类的实例。这不是这个问题的必要条件,但是 similar one .

        2
  •  1
  •   Community Egal    7 年前

    How do you retrieve items from a dictionary in the order that they're inserted?

    您可以通过复制其中一个实现来创建自己的OrderedDict模块,以便在自己的代码中使用。我假设您没有访问OrderedDict的权限,因为您运行的是Python版本。

    您问题的一个有趣方面是可能需要defaultdict功能。如果需要,可以实现 __missing__ 方法以获得所需的效果。

        3
  •  1
  •   Florian Reiser    8 年前

    class OrderedDefaultDict(OrderedDict):
        #Implementation as suggested by martineau
    
        def copy(self):
             return type(self)(self.default_factory, self)
    

    请考虑,这个实现没有deepcopy,这在大多数情况下似乎特别适合默认字典