【问题标题】:Creating separate dictionaries with a list of values in it创建单独的字典,其中包含值列表
【发布时间】:2022-01-21 21:57:42
【问题描述】:

我有一本这样的字典:

d = {
    'hosts': [
        {'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'},
        {'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it,check-this'},
        {'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me,check-this,check-it'}
    ]
}

我想用它创建以下字典

d = {
    'hosts': [
        {'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'},
        {'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it'},
        {'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-this'},
        {'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'},
        {'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'},
        {'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'}
        {'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-it'},
        {'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-it'},
        {'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-it'}
        {'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-this'},
        {'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-this'},
        {'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-this'}
    ]
}

这意味着每个值列表都应该有一个单独的子字典,只要给出了值列表。

【问题讨论】:

    标签: python-3.x dictionary data-structures key-value


    【解决方案1】:

    也许是这样的?

    def expand_dict(host):
        # Create all of the possible key-value pairs for each key in the original dictionary
        kv_pairs = [[(k, v) for v in vals.split(",")] for k, vals in host.items()]
        # Find the number of dictionaries this would expand to
        max_len = max(len(p) for p in kv_pairs)
        # A list of possible values must either be the length of the number of dictionaries we expect, or length 1 so we can repeat the value max_len times
        assert all(len(pairs) in {1, max_len} for pairs in kv_pairs)
        # Expand all of the length 1 value lists to length max_len
        updated_pairs = [p if len(p) == max_len else p * max_len for p in kv_pairs]
        # Return a generator of dictionaries for each of the sets of key-value pairs
        return (dict(pairs) for pairs in zip(*updated_pairs))
    
    input_dict = {'hosts': [{'hostname': 'abc', 'ip': '127.0.0.1', 'extra_check_cmd': 'check-me'}, {'hostname': 'def', 'ip': '127.0.0.2', 'extra_check_cmd': 'check-it,check-this'}, {'hostname': 'ijk,uvw,xyz', 'ip': '127.0.0.3,127.0.0.4,127.0.0.5', 'extra': 'check-me'}]}
    output_dict = {'hosts': [d for host in input_dict['hosts'] for d in expand_dict(host)]}
    

    进一步分解,让我们用一个例子来试试。在这种情况下,我使用的是host = d['hosts'][2]

    {'hostname': 'ijk,uvw,xyz',
     'ip': '127.0.0.3,127.0.0.4,127.0.0.5',
     'extra': 'check-me'}
    

    kv_pairs = [[(k, v) for v in vals.split(",")] for k, vals in host.items()] 行为我们提供了内部项目列表的可能键值对列表。

    [
        [('hostname', 'ijk'), ('hostname', 'uvw'), ('hostname', 'xyz')],
        [('ip', '127.0.0.3'), ('ip', '127.0.0.4'), ('ip', '127.0.0.5')],
        [('extra', 'check-me')],
    ]
    

    如您所见,"hostname""ip" 键各有 3 个键值对,而 "extra" 键在原始主机字典中只有 1 个键值对。目标是生成 3 个字典,每个字典都带有 'extra': 'check-me'。所以,我们想找出我们期望生成的字典数量。

    max_len = max(len(p) for p in kv_pairs) 行给了我们 3。然后,作为健全性检查,我们要确保 kv_pairs 中的每组键值对的长度为 1 或长度为 3。如果是其他, 问题不会很好定义,所以我们添加断言assert all(len(pairs) in {1, max_len} for pairs in kv_pairs)

    然后我们通过重复将所有长度为 1 kv 的对列表扩展为长度为 3。这个列表理解基本上采用所有长度为 3 的列表,并将长度为 1 的列表重复 3 次,因此它们的长度都相同。

    updated_pairs = [p if len(p) == max_len else p * max_len for p in kv_pairs]
    
    [[('hostname', 'ijk'), ('hostname', 'uvw'), ('hostname', 'xyz')],
     [('ip', '127.0.0.3'), ('ip', '127.0.0.4'), ('ip', '127.0.0.5')],
     [('extra', 'check-me'), ('extra', 'check-me'), ('extra', 'check-me')]]
    

    现在一切都准备好了,我们可以开始创建字典了。我们可以为此使用zip(),它为我们提供了元组的迭代器,其中包含来自我们传入的每个输入迭代器的项目。我正在使用Python 的解包语法将updated_kv_pairs 中的每个列表扩展为zip() 的单独参数.换句话说,

    zip(*updated_kv_pairs)
    

    相同
    zip(updated_kv_pairs[0], updated_kv_pairs[1], updated_kv_pairs[2])
    

    zip() 的每次迭代都会为我们提供一个键值对列表,这些键值对位于我们输出的单个字典中。这给了我们

    {'hostname': 'ijk', 'ip': '127.0.0.3', 'extra': 'check-me'}
    {'hostname': 'uvw', 'ip': '127.0.0.4', 'extra': 'check-me'}
    {'hostname': 'xyz', 'ip': '127.0.0.5', 'extra': 'check-me'}
    

    【讨论】:

    • 是的,我没有在我的代码中的任何地方使用 dict,它只是为了在这里进行解释。非常感谢您的及时回复。
    • @HardySandhu Weeeeeell 你试过了吗? ;-)
    • @rchome 这个答案中的代码很棒,但旁边的文字解释会更好!
    • 我也无法通过pythontutor.com 理解它。稍微解释一下会更好。
    • 我已经用一些 cmets 更新了代码。让我知道是否有任何需要澄清的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-04
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多