我是一个新工具,它会帮助我以这种形式收集数据: [{Entity:{Field:Value}},...]
除非另有说服力,否则这就是我表达数据的方式:
alldata = [
{'ShinyCorp, Inc.' :
[
{'state' : 'CA'},
{'phone' : '123-456-7890'}
]
},
{'MultiBiz, LLC' :
[
{'state' : 'NY'},
{'ceo' : 'Glenn Suggzass'}
]
},
{'Marx Capital Group' :
[
{'state' : 'DE'},
{'fax' : '321-654-0987'}
]
}
]
我想以两种形式呈现数据:
1)实体名称列表作为第一列,每行的列显示此列的第一个列中列出的实体的字段值的行
2)字段名称列表作为第一列,每行的列显示此行的第一个行中列出的实体的字段值列(又名标题)
像这样...
1)
EntityName state phone ceo fax
ShinyCorp, Inc. CA 123-456-7890
MultiBiz, LLC NY Glenn Suggzass
Marx Capital Group DE 321-654-0987
2)
FieldName ShinyCorp, Inc. MultiBiz, LLC Marx Capital Group
state CA NY DE
phone 123-456-7890
ceo Glenn Suggzass
fax 321-654-0987
所以,...
考虑到alldata(EntityName-ordiented dicts列表)的格式,为DictWriter和writer写入格式1)和2)的迭代的列表推导是什么。
编辑:这只是一个玩具示例,目的是获得一些好的列表理解建议。
答案 0 :(得分:0)
这个非常老的问题,您仍然存在的机会很少,但是这个问题很有趣。
首先,我认为您的数据结构不是最好的。假设您从csv文件中获得了这样的元组:
>>> csv = [('ShinyCorp, Inc.', 'state', 'CA'),
... ('ShinyCorp, Inc.', 'phone', '123-456-7890'),
... ('MultiBiz, LLC', 'state', 'NY'),
... ('MultiBiz, LLC', 'ceo', 'Glenn Suggzass'),
... ('Marx Capital Group', 'state', 'DE'),
... ('Marx Capital Group', 'fax', '321-654-0987')]
您必须列出实体和字段及其关系。如果您不关心订单:
>>> data_by_entity = {}
>>> fields = set()
>>> for entity,k,v in csv:
... fields.add(k)
... data_by_entity.setdefault(entity, {})[k] = v
...
>>> data_by_entity
{'ShinyCorp, Inc.': {'state': 'CA', 'phone': '123-456-7890'}, 'MultiBiz, LLC': {'state': 'NY', 'ceo': 'Glenn Suggzass'}, 'Marx Capital Group': {'state': 'DE', 'fax': '321-654-0987'}}
>>> sorted(fields)
['ceo', 'fax', 'phone', 'state']
>>> sorted(data_by_entity.keys())
['Marx Capital Group', 'MultiBiz, LLC', 'ShinyCorp, Inc.']
如果您关心订单:
>>> data_by_entity = {}
>>> fseen = set()
>>> fields = []
>>> eseen = set()
>>> entities = []
>>> for entity,k,v in csv:
... if entity not in eseen:
... entities.append(entity)
... data_by_entity[entity] = {}
... eseen.add(entity)
... if k not in fseen:
... fields.append(k)
... fseen.add(k)
... data_by_entity[entity][k]=v
...
>>> data_by_entity
{'ShinyCorp, Inc.': {'state': 'CA', 'phone': '123-456-7890'}, 'MultiBiz, LLC': {'state': 'NY', 'ceo': 'Glenn Suggzass'}, 'Marx Capital Group': {'state': 'DE', 'fax': '321-654-0987'}}
>>> fields
['state', 'phone', 'ceo', 'fax']
>>> entities
['ShinyCorp, Inc.', 'MultiBiz, LLC', 'Marx Capital Group']
seen
技巧保留了列表中的一组元素。当(且仅当)元素不在列表中(即...不在集合中(O(1)vs 0(n)速度))时,才添加元素。
此数据结构可以轻松更新:在循环主体中添加一个新的元组。
>>> alldata = [
... {'ShinyCorp, Inc.' :
... [
... {'state' : 'CA'},
... {'phone' : '123-456-7890'}
... ]
... },
...
... {'MultiBiz, LLC' :
... [
... {'state' : 'NY'},
... {'ceo' : 'Glenn Suggzass'}
... ]
... },
...
... {'Marx Capital Group' :
... [
... {'state' : 'DE'},
... {'fax' : '321-654-0987'}
... ]
... }
... ]
>>> data_by_entity = {e:{k:v for value in values for k,v in value.items()} for data in alldata for e, values in data.items()}
>>> data_by_entity
{'ShinyCorp, Inc.': {'state': 'CA', 'phone': '123-456-7890'}, 'MultiBiz, LLC': {'state': 'NY', 'ceo': 'Glenn Suggzass'}, 'Marx Capital Group': {'state': 'DE', 'fax': '321-654-0987'}}
说明:
for data in alldata
:这是外在命令for e, values in data.items()
:实体和内部字典的列表{k:v for value in values for k,v in value.items()}
:这会合并列表values
中存在的内部字典。使用merge_list_of_dicts
函数可能更容易理解:
>>> def merge_list_of_dicts(L): return {k: v for d in L for k,v in d.items()}
>>> data_by_entity = {e:merge_list_of_dicts(values) for e, values in merge_list_of_dicts(alldata).items()}
>>> data_by_entity
{'ShinyCorp, Inc.': {'state': 'CA', 'phone': '123-456-7890'}, 'MultiBiz, LLC': {'state': 'NY', 'ceo': 'Glenn Suggzass'}, 'Marx Capital Group': {'state': 'DE', 'fax': '321-654-0987'}}
从结构中获取字段很容易:
>>> fields = set(k for data in data_by_entity.values() for k,v in data.items())
>>> sorted(fields)
['ceo', 'fax', 'phone', 'state']
现在,问题的答案。
>>> fields = sorted(fields) # ensure the test is reproducible
>>> [["EntityName"]+fields]+[[k]+[v.get(f, "") for f in fields] for k, v in data_by_entity.items()]
[['EntityName', 'ceo', 'fax', 'phone', 'state'], ['ShinyCorp, Inc.', '', '', '123-456-7890', 'CA'], ['MultiBiz, LLC', 'Glenn Suggzass', '', '', 'NY'], ['Marx Capital Group', '', '321-654-0987', '', 'DE']]
说明:
["EntityName"]+fields]
是第一行; [k]+[v.get(f, "") for f in fields]
遍历字段并获取值。它以字段名称k
开头; [[k]+[...] for k, v in data_by_entity.items()]
对每个实体重复上面的列表。>>> [["FieldName"]+entities]+[[k]+[data_by_entity[e].get(k, "") for e in entities] for k in fields]
[['FieldName', 'ShinyCorp, Inc.', 'MultiBiz, LLC', 'Marx Capital Group'], ['ceo', '', 'Glenn Suggzass', ''], ['fax', '', '', '321-654-0987'], ['phone', '123-456-7890', '', ''], ['state', 'CA', 'NY', 'DE']]
说明:
["FieldName"]+entities]
是第一行; [k]+[data_by_entity[e].get(k, "") for e in entities]
遍历实体,并获取给定k
的值。它以字段名称k
开头; [[k]+[...] for k in fields]
对每个字段重复上面的列表。这是另一个版本
>>> L = [["EntityName"]+list(fields)]+[[k]+[v.get(f, "") for f in fields] for k, v in data_by_entity.items()]
>>> list(zip(*L))
[('EntityName', 'ShinyCorp, Inc.', 'MultiBiz, LLC', 'Marx Capital Group'), ('ceo', '', 'Glenn Suggzass', ''), ('fax', '', '', '321-654-0987'), ('phone', '123-456-7890', '', ''), ('state', 'CA', 'NY', 'DE')]
说明:list(zip(*L)
是转置列表列表的惯用方式。如果L = [L1, ..., Ln]
,则zip(*L)
将列表解压缩到zip(L1, ..., Ln)
。然后zip
用每个列表的第一个元素创建一个元组,用每个列表的第二个元素创建另一个元组,...直到用尽列表中的一个。