Python:将多个嵌套列表组合成一个字典

发布于 2024-10-31 07:35:12 字数 346 浏览 1 评论 0原文

我有一堆类似以下两个的列表:

['a', ['b', ['x', '1'], ['y', '2']]]
['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]

将所有这些列表组合成一个字典的最简单方法是什么,如下所示:

{'a': {
    'b': {
        'x':1,
        'y':2
    }
    'c': {
        'xx':4,
        'gg': {
            'm':3
        }
    }
}

嵌套的深度是可变的。

I have a bunch of lists like the following two:

['a', ['b', ['x', '1'], ['y', '2']]]
['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]

What is the easiest way to combine all of them into a single dictionary that looks like:

{'a': {
    'b': {
        'x':1,
        'y':2
    }
    'c': {
        'xx':4,
        'gg': {
            'm':3
        }
    }
}

The depth of nesting is variable.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

林空鹿饮溪 2024-11-07 07:35:12

这是一个非常粗略的实现,它不处理奇怪的情况,例如少于两个元素的列表,并且它会覆盖重复的键,但它可以帮助您开始:

l1 = ['a', ['b', ['x', '1'], ['y', '2']]]
l2 = ['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]

def combine(d, l):
    if not l[0] in d:
        d[l[0]] = {}

    for v in l[1:]:
        if type(v) == list:
            combine(d[l[0]],v)
        else:
            d[l[0]] = v

h = {}
combine(h, l1)
combine(h, l2)
print h

输出:

{'a': {'c': {'gg': {'m': '3'}, 'xx': '4'}, 'b': {'y': '2', 'x': '1'}}}

Here's a very crude implementation, it does not handle weird cases such as lists having less than two elements and it overwrites duplicate keys, but its' something to get you started:

l1 = ['a', ['b', ['x', '1'], ['y', '2']]]
l2 = ['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]

def combine(d, l):
    if not l[0] in d:
        d[l[0]] = {}

    for v in l[1:]:
        if type(v) == list:
            combine(d[l[0]],v)
        else:
            d[l[0]] = v

h = {}
combine(h, l1)
combine(h, l2)
print h

Output:

{'a': {'c': {'gg': {'m': '3'}, 'xx': '4'}, 'b': {'y': '2', 'x': '1'}}}
风筝在阴天搁浅。 2024-11-07 07:35:12

这并不是真正的“Pythonic”,但我没有找到一种无需递归即可做到这一点的好方法

def listToDict(l):
    if type(l) != type([]): return l
    return {l[0] : listToDict(l[1])}

It's not really 'pythonic' but i dont see a good way to do this without recursion

def listToDict(l):
    if type(l) != type([]): return l
    return {l[0] : listToDict(l[1])}
萌面超妹 2024-11-07 07:35:12

对我来说,将这个问题分成两部分是最有意义的(好吧,我第一次通过......'S读错了这个问题)

转换

第一部分转换[key, list1, list2] 数据结构嵌套字典:

def recdict(elements):
    """Create recursive dictionaries from [k, v1, v2, ...] lists.

    >>> import pprint, functools
    >>> pprint = functools.partial(pprint.pprint, width=2)
    >>> pprint(recdict(['a', ['b', ['x', '1'], ['y', '2']]]))
    {'a': {'b': {'x': '1',
                 'y': '2'}}}
    >>> pprint(recdict(['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]))
    {'a': {'c': {'gg': {'m': '3'},
                 'xx': '4'}}}
    """

    def rec(item):
        if isinstance(item[1], list):
            return [item[0], dict(rec(e) for e in item[1:])]

        return item

    return dict([rec(elements)])

要求

  • 每个列表至少有两个元素,
  • 每个列表的第一个元素是键,
  • 如果列表的第二个元素是列表,则所有后续元素也是列表;这些被组合成一本字典。

棘手的一点(至少对我来说)是意识到你必须从递归函数返回一个列表而不是字典。否则,您无法组合形成某些列表的第二个和第三个元素的并行列表。

为了使其更普遍有用(即对于元组和其他序列),我将更改为

if isinstance(item[1], list):

You

if (isinstance(item[1], collections.Sequence)
    and not isinstance(item[1], basestring)):

can also make it work for any iterable 但这需要一点重组。

合并

第二部分合并在两个给定数据结构上运行第一个例程所产生的字典。我认为这将递归地合并任意数量的没有冲突键的字典,尽管除了这个用例之外我没有真正测试它。

def mergedicts(*dicts):
    """Recursively merge an arbitrary number of dictionaries.
    >>> import pprint
    >>> d1 = {'a': {'b': {'x': '1',
    ...                   'y': '2'}}}
    >>> d2 = {'a': {'c': {'gg': {'m': '3'},
    ...                   'xx': '4'}}}
    >>> pprint.pprint(mergedicts(d1, d2), width=2)
    {'a': {'b': {'x': '1',
                 'y': '2'},
           'c': {'gg': {'m': '3'},
                 'xx': '4'}}}
    """

    keys = set(k for d in dicts for k in d)

    def vals(key):
        """Returns all values for `key` in all `dicts`."""
        withkey = (d for d in dicts if d.has_key(key))
        return [d[key] for d in withkey]

    def recurse(*values):
        """Recurse if the values are dictionaries."""
        if isinstance(values[0], dict):
            return mergedicts(*values)
        if len(values) == 1:
            return values[0]
        raise TypeError("Multiple non-dictionary values for a key.")

    return dict((key, recurse(*vals(key))) for key in keys)

It made the most sense to me to break this problem into two parts (well, that and I misread the question the first time through..'S)

transformation

The first part transforms the [key, list1, list2] data structure into nested dictionaries:

def recdict(elements):
    """Create recursive dictionaries from [k, v1, v2, ...] lists.

    >>> import pprint, functools
    >>> pprint = functools.partial(pprint.pprint, width=2)
    >>> pprint(recdict(['a', ['b', ['x', '1'], ['y', '2']]]))
    {'a': {'b': {'x': '1',
                 'y': '2'}}}
    >>> pprint(recdict(['a', ['c', ['xx', '4'], ['gg', ['m', '3']]]]))
    {'a': {'c': {'gg': {'m': '3'},
                 'xx': '4'}}}
    """

    def rec(item):
        if isinstance(item[1], list):
            return [item[0], dict(rec(e) for e in item[1:])]

        return item

    return dict([rec(elements)])

It expects that

  • every list has at least two elements
  • the first element of every list is a key
  • if the second element of a list is a list, then all subsequent elements are also lists; these are combined into a dictionary.

The tricky bit (at least for me) was realizing that you have to return a list from the recursive function rather than a dictionary. Otherwise, you can't combine the parallel lists that form the second and third elements of some of the lists.

To make this more generally useful (i.e. to tuples and other sequences), I would change

if isinstance(item[1], list):

to

if (isinstance(item[1], collections.Sequence)
    and not isinstance(item[1], basestring)):

You can also make it work for any iterable but that requires a little bit of reorganization.

merging

The second part merges the dictionaries that result from running the first routine on the two given data structures. I think this will recursively merge any number of dictionaries that don't have conflicting keys, though I didn't really test it for anything other than this use case.

def mergedicts(*dicts):
    """Recursively merge an arbitrary number of dictionaries.
    >>> import pprint
    >>> d1 = {'a': {'b': {'x': '1',
    ...                   'y': '2'}}}
    >>> d2 = {'a': {'c': {'gg': {'m': '3'},
    ...                   'xx': '4'}}}
    >>> pprint.pprint(mergedicts(d1, d2), width=2)
    {'a': {'b': {'x': '1',
                 'y': '2'},
           'c': {'gg': {'m': '3'},
                 'xx': '4'}}}
    """

    keys = set(k for d in dicts for k in d)

    def vals(key):
        """Returns all values for `key` in all `dicts`."""
        withkey = (d for d in dicts if d.has_key(key))
        return [d[key] for d in withkey]

    def recurse(*values):
        """Recurse if the values are dictionaries."""
        if isinstance(values[0], dict):
            return mergedicts(*values)
        if len(values) == 1:
            return values[0]
        raise TypeError("Multiple non-dictionary values for a key.")

    return dict((key, recurse(*vals(key))) for key in keys)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文