将包含列表项的字典扩展为字典对列表

时间:2018-06-24 01:38:05

标签: python python-2.7 dictionary list-comprehension dictionary-comprehension

如果我有一个字典,在其一个或多个值中包含列表:

data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}

如何获取由pair配对并遍历c的字典元组列表,而其他所有常量保持不变?例如

output = [
    ({
        'a':0,
        'b':1,
        'c':0,
        'pair':'one'
    },
    {
        'a':0,
        'b':1,
        'c':0,
        'pair':'two'
    }),
    ({
        'a':0,
        'b':1,
        'c':1,
        'pair':'one'
    },
    ...
]

6 个答案:

答案 0 :(得分:5)

嗯,这感觉并不特别优雅,但是您可以使用嵌套的for循环或列表理解:

output = []
for i in data['c']:
  output.append(tuple({'a': 0, 'b': 1, 'c': i, 'pair': p} for p in data))

output = [tuple({'a': 0, 'b': 1, 'c': i, 'pair': p} for p in data['pair']) for i in data['c']]

更清洁的解决方案可能会将组件dict的生成分离为一个函数,如下所示:

def gen_output_dict(c, pair):
  return {'a': 0, 'b': 1, 'c': c, 'pair': pair}

output = []
for i in data['c']:
  output.append(tuple(gen_output_dict(i, p) for p in data['pair']))

答案 1 :(得分:4)

您可以在列表值上使用itertools.product并跟踪每个元素源自的键。由于键'pair'具有特殊含义,因此您应该单独对待它。

代码

from itertools import product

def unzip_dict(d):
    keys = [k for k, v in d.items() if isinstance(v, list) and k != 'pair']
    values = [d[k] for k in keys]

    for values in product(*values):
        yield tuple({**d, **dict(zip(keys, values)), 'pair': pair} for pair in d['pair'])

示例

data = {
    'a': 0,
    'c': [1, 2],
    'pair': ['one', 'two']
}

print(*unzip_dict(data))

输出

({'a': 0, 'c': 1, 'pair': 'one'}, {'a': 0, 'c': 1, 'pair': 'two'})
({'a': 0, 'c': 2, 'pair': 'one'}, {'a': 0, 'c': 2, 'pair': 'two'})

答案 2 :(得分:1)

以下是扩展的解决方案:

data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}

# Get the length of the longest sequence
length = max(map(lambda x: len(x) if isinstance(x, list) else 1, data.values()))

# Loop through the data and change scalars to sequences
# while also making sure that smaller sequences are stretched to match
# or exceed the length of the longest sequence
for k, v in data.items():
    if isinstance(v, list):
        data[k] = v * int(round(length/len(v), 0))
    else:
        data[k] = [v] * length

# Create a dictionary to keep track of which outputs
# need to end up in which tuple
seen = dict.fromkeys(data.get('pair'), 0)
output = [tuple()] * len(seen)

# Loop through the data and place dictionaries in their
# corresponding tuples.
for v in zip(*data.values()):
        d = dict(zip(data, v))
        output[seen[d.get('pair')]] += (d,)
        seen[d.get('pair')] += 1

print(output)

该想法是将数据中的标量转换为长度与原始数据中最长序列的长度匹配的序列。因此,我要做的第一件事是将最长序列的大小分配给变量length。有了这些知识,我们便可以遍历原始数据并扩展现有序列以匹配最长序列的大小,同时将标量转换为序列。 完成后,我们将继续生成output变量。但是首先,我们创建一个名为seen的字典,以帮助我们创建元组列表并跟踪哪个字典组最终位于哪个元组中。 然后,这使我们可以运行最后一个循环,以将字典组放置到其对应的元组中。

当前输出如下:

[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
  {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
 ({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},)]

如果您需要更多澄清信息,请告诉我。否则,我希望这样做有一定目的。

答案 3 :(得分:1)

@ r3robertson ,您也可以尝试以下代码。该代码基于Python中list comprehensiondeepcopy() operation的概念。

  

选中Shallow copy vs deepcopy in Python

import pprint;
import copy;

data = {
    'a': 0,
    'b': 1,
    'c': [0, 1, 2],
    'pair': ['one','two'],
};

def get_updated_dict(data, index, pair_name):
    d = copy.deepcopy(data);
    d.update({'c': index, 'pair': pair_name});
    return d;

output = [tuple(get_updated_dict(data, index, pair_name) for pair_name in data['pair']) for index in data['c']];

# Pretty printing the output list.
pprint.pprint(output, indent=4);

输出»

[   (   {   'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
    (   {   'a': 0, 'b': 1, 'c': 1, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
    (   {   'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},
        {   'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]

使用json模块进行漂亮的打印»

  

注意:元组将在此处转换为列表,因为JSON中不支持元组。

import json;
print(json.dumps(output, indent=4));

输出»

[
    [
        {
            "a": 0,
            "c": 0,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 0,
            "b": 1,
            "pair": "two"
        }
    ],
    [
        {
            "a": 0,
            "c": 1,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 1,
            "b": 1,
            "pair": "two"
        }
    ],
    [
        {
            "a": 0,
            "c": 2,
            "b": 1,
            "pair": "one"
        },
        {
            "a": 0,
            "c": 2,
            "b": 1,
            "pair": "two"
        }
    ]
]

答案 4 :(得分:0)

不太完美,但这是我的解决方法。

Layout: <CGRecordLayout
  LLVMType:%struct.Base = type { i32 }
  NonVirtualBaseLLVMType:%struct.Base = type { i32 }
  IsZeroInitializable:1
  BitFields:[
]>

Layout: <CGRecordLayout
  LLVMType:%struct.Derived = type { %struct.Base, i32 }
  NonVirtualBaseLLVMType:%struct.Derived = type { %struct.Base, i32 }
  IsZeroInitializable:1
  BitFields:[
]>

答案 5 :(得分:-1)

您可以使用//works let test = prompt("testing","aasdasd"); if (test === null) { console.log("cancel"); } else { console.log("ok"); } let inpname; //do not work let func = () => { while (true) { try { inpname = prompt("name ", "name here"); if (inpname.length > 10 || inpname.length <= 3) { throw "Your name must be at least 10 characters long, but not less than 4"; } else if ( inpname != inpname.match(/^[a-zA-Z]+$/)) { throw "A-Z characters accepted only!"; } //problem here! else if (inpname === null) { throw "cant cancel"; } else { console.log("success"); break } } catch (err) { console.log(err); break } } } func();

itertools

输出:

import itertools
data = {
  'a':0,
  'b':1,
  'c':[0, 1, 2],
  'pair':['one','two']
}
def expand_dict(data):
   grouped = [a for a, b in data.items() if isinstance(b, list)]
   p = [[a, list(b)] for a, b in itertools.groupby(itertools.product(*[data[i] for i in grouped]), key=lambda x:x[0])]
   return [tuple({**data, **dict(zip(grouped, i))} for i in c) for _, c in p]

print(expand_dict(data))

此解决方案也可用于具有许多可能值列表的输入:

[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}), 
 ({'a': 0, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}), 
 ({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]

输出:

data = {'a':[5, 6, 1, 3], 'b':1, 'c':[0, 1, 2], 'pair':['one', 'two']}
print(expand_dict(data))