【问题标题】:Rotating tablular CSV data with list comprehensions使用列表推导旋转表格 CSV 数据
【发布时间】:2013-11-13 04:40:54
【问题描述】:

我刚刚开发了一个工具,可以帮助我以这种形式收集数据:[{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) entity 名称列表作为第一列,每行的列显示第一个 column 中列出的实体的字段值

2) field 名称列表作为第一列,每行的列显示列在此第一个 row 中的实体的字段值(又名标题)

就这样……

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 的格式(面向实体名称的 dicts 的列表),哪些列表推导式为 DictWriter 和 writerows 提供了编写格式 1) 和 2) 的可迭代对象。

编辑:这只是一个玩具示例,目的是获得一些好的列表理解建议。

【问题讨论】:

  • 为什么是[{'state': 'CA'}, {'phone': '123-456-7890'}] 而不是{'state': 'CA', 'phone': '123-456-7890'}? (上一级也一样,但我猜你可能有两行公司信息。)
  • 好问题。该工具旨在逐步整理和组织小的、广泛的互联网信息位,并将其组织成您所描述的组织良好的结构。这就是为什么数据以这种基本方式(实体:键:值)表示的原因。

标签: python csv dictionary list-comprehension


【解决方案1】:

非常老的问题,你仍然存在的机会很少,但这个问题很有趣。

更简单的数据结构

首先,我认为你的数据结构不是最好的。假设你得到这样的元组(来自 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)与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 用每个列表的第一个元素创建一个元组,用每个列表的第二个元素创建另一个元组,......直到它耗尽一个列表。

【讨论】:

    猜你喜欢
    • 2020-10-08
    • 1970-01-01
    • 2019-07-13
    • 2011-07-24
    • 1970-01-01
    • 2022-11-18
    • 2020-02-22
    • 2020-02-23
    • 1970-01-01
    相关资源
    最近更新 更多