当单个键有多个值时拆分Python字典

时间:2019-05-02 11:25:35

标签: python

我有一些Python字典,对于单个键,有时会有多个用逗号分隔的值(例如“ value1,value2”)。在这些情况下,我需要将字典分成多个多个值(有关所需输出的示例,请参见问题底部)。字典中每个键只能有一个值,否则它必须是一个完全独立的字典。

我试图遍历字典并在找到具有多个值的值时使用popitem函数。然后创建单独的字典并追加它们。但是我遇到了运行时错误。而且我怀疑还有其他更优雅的解决方案。

例如

x = {"name":"alice", "age":20,"hobby":"badminton, basketball", "language":"python"}
for eachkey, value in x.items():
    if ", " in value:
        x.popitem()

在进一步了解之前,请获取以下错误:

RuntimeError: dictionary changed size during iteration

这是预期输入和输出的示例:

输入

x = {"name":"alice", "age":20,"hobby":"badminton, basketball", "language":"python"}

输出

[
    {"name":"alice", "age":20,"hobby":"badminton", "language":"python"},
    {"name":"alice", "age":20,"hobby":"basketball", "language":"python"}
]

或另一个带有具有多个值的多个键的示例
(已编辑+包括在内,以在@isaactfa回答后进行澄清)

输入

x = {"name":"alice", "age":20,"hobby":"badminton, basketball", "language":"python, go"}

输出

[
    {'name': 'alice', 'age': 20, 'hobby': 'badminton', 'language': 'python'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'badminton', 'language': 'go'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'basketball', 'language': 'python'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'basketball', 'language': 'go'}
]

3 个答案:

答案 0 :(得分:4)

我将从将输入转换为键值元组列表的列表开始(好吧)

def unwrap(d):
    for k, v in d.items():
        if isinstance(v, str):
            yield [(k, v2.strip()) for v2 in v.split(',')]
        else:
            yield [(k, v)]

这样

d = {
    "name": "alice",
    "age": 20,
    "hobby": "badminton, basketball",
    "language": "python, go"
}

它将返回

[
    [('name', 'alice')], 
    [('age', 20)], 
    [('hobby', 'badminton'), ('hobby', 'basketball')], 
    [('language', 'python'), ('language', 'go')]
]

完成此操作后,应用itertools.product将其转换为所有可能的字典列表:

result = [
    dict(x)
    for x in product(*unwrap(d))
]

result

[
    {'name': 'alice', 'age': 20, 'hobby': 'badminton', 'language': 'python'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'badminton', 'language': 'go'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'basketball', 'language': 'python'}, 
    {'name': 'alice', 'age': 20, 'hobby': 'basketball', 'language': 'go'}
]

答案 1 :(得分:2)

您可以使用函数product()

from itertools import product

x = {"name":"alice", "age":20,"hobby":"badminton, basketball", "language":"python"}

vals = [v.split(', ') if isinstance(v, str) else [v] for v in x.values()]
print([dict(zip(x, p)) for p in product(*vals)])

输出:

[{'name': 'alice', 'age': 20, 'hobby': 'badminton', 'language': 'python'},
 {'name': 'alice', 'age': 20, 'hobby': 'basketball', 'language': 'python'}]

答案 2 :(得分:1)

编辑:如果一个以上的键具有多个值,则这不会产生字典的所有排列。如果这是您需要的,请查看@georg的答案。

原始答案

这应该为您提供所需的输出:

def make_dicts(x):
    tuples = [(k, *(s.strip() for s in v.split(","))) if isinstance(v, str) else (k, v) for k, v in x.items()]
    most_values = max(len(t) for t in tuples) - 1
    for i in range(most_values):
        yield {k: v[i % len(v)] for k, *v in tuples}

您现在可以遍历make_dicts(x)来检索您的新词典,或者执行list(make_dicts(x))将它们放在列表中。

它的工作方式是,首先创建一个元组列表,其中包含键作为第一个元素,其后每个逗号分隔的值。然后,我找到那些元组中最大的元组,因为这将创建多少个新字典(键减去1)。现在,对于每一个新字典,我都告诉它放一个键,然后放下一个值,并用模数包装索引,这样只有一个值的键就会重复。

希望这就是您想要的。