[英]Pack a list of dicts in python
我有这样的字典结构:
[
{'state': '1', 'city': 'a'},
{'state': '1', 'city': 'b'},
{'state': '2', 'city': 'c'},
{'state': '2', 'city': 'd'},
{'state': '3', 'city': 'e'}
]
我想用这种方式打包:
[
{'state': '1', 'cities': ['a', 'b']},
{'state': '2', 'cities': ['c', 'd']},
{'state': '3', 'cities': ['e']}
]
我有一个两步式的方法可以工作,但是很慢(我的列表超过10000个项目,我的字典很复杂):
def pack(iterable):
# step 1: lists -> super slow ! contains duplicates
listed = [{'state': i['state'],
'cities': [c['city'] for c in iterable if c['state']==i['state']]}
for i in iterable]
# step 2: remove duplicates
packed = [l for n, l in enumerate(listed) if not l in listed[n+1:]]
return packed
有什么优化建议吗?
附:欢迎提供有关线程标题的建议。
2014/09/26的编辑:我刚刚发现了熊猫非标准库,在这种情况下很有用。
下面的自我解答中有更多示例。
state_merged = {}
for s in states:
state_merged.setdefault(s['state'], []).append(s['city'])
states = [{'state':k, 'cities':v} for k, v in state_merged.iteritems()]
如果您使用的是python 3.0,请使用state_merged.items()
代替,如果使用state_merged.iteritems()
以下代码不需要预先排序的可迭代对象,并且可以在O(n)
时间内运行,但是它假定状态和其他字典键之间是不对称的(在您的示例中,这似乎是正确的假设)。
import collections
def pack(iterable):
out = collections.defaultdict(list) #or use defaultdict(set)
for d in iterable:
out[d['state']].append(d['city'])
return out
it = [
{'state': '1', 'city': 'a'},
{'state': '1', 'city': 'b'},
{'state': '2', 'city': 'c'},
{'state': '2', 'city': 'd'},
{'state': '3', 'city': 'e'}
]
pack(it) == {'1': ['a', 'b'],
'2': ['c', 'd'],
'3': ['e']}
如果你需要的要求,在相同的格式返回一个迭代器,你可以转换out
成一个list
。
def convert(out):
final = []
for state, city in out.iteritems(): #Python 3.0+ use .items()
final.append({'state': state, 'city': city})
return final
convert(pack(it)) == [
{'state': '1', 'city': ['a', 'b']},
{'state': '2', 'city': ['c', 'd']},
{'state': '3', 'city': ['e']}
]
如果您输入的不仅仅是两个键,则需要进行以下更改:
it = [{'state': 'WA', 'city': 'Seattle', 'zipcode': 98101, 'city_population': 9426},
{'state': 'OR', 'city': 'Portland', 'zipcode': 97225, 'city_population': 24749},
{'state': 'WA', 'city': 'Spokane', 'zipcode': 99201, 'city_population': 12523}]
def citydata():
return {'city': [], 'zipcode': [], 'state_population': 0} #or use a namedtuple('Location', 'city zipcode state_population')
def pack(iterable):
out = defaultdict(citydata)
for d in iterable:
out[d['state']]['city'].append(d['city'])
out[d['state']]['zipcode'].append(d['zipcode'])
out[d['state']]['state_population'] += d['city_population']
return out
pack(it) == {
'WA':
{'city': ['Seattle', 'Spokane'], 'zipcode': [98101, 99201], 'state_population': 21949},
'OR':
{'city': ['Portland'], 'zipcode': [97225], 'state_population': 24749}
}
convert
功能需要相应地进行调整。
convert(pack(it)) == [
{'state': 'WA', 'city': ['Seattle', 'Spokane'], 'zipcode': [98101, 99201], 'state_population': 21949},
{'state': 'OR', 'city': ['Portland'], 'zipcode': [97225], 'state_population': 24749}
]
为了保持原始可迭代对象的顺序,请使用OrderedDefaultdict而不是defaultdict。
这是一种更加实用的方法,速度更快:
import itertools
def pack(original):
return [
{'state': state, 'cities': [element['city'] for element in group]}
for state, group
in itertools.groupby(original, lambda e: e['state'])
]
假设您的每个州在原始列表中连续列出了其所有成员。
您当前的方法之所以慢得多的原因是,它必须对找到的每个状态ID遍历整个列表。 这被称为O(n^2)
方法。 这种方法只需要对源列表进行一次迭代,所以它是O(n)
。
我在Windows python 2.6.5上安装了一些麻烦后才发现了pandas lib(这是非标准的)(exe在这里http://www.lfd.uci.edu/~gohlke/pythonlibs/#pandas )。
网站: http : //pandas.pydata.org/pandas-docs/stable/
总体介绍:
pandas是一个Python软件包,提供快速,灵活和富于表现力的数据结构,旨在使使用“关系”或“标记”数据既简单又直观。 它旨在成为在Python中进行实际,真实世界数据分析的基本高级构建块。
已经使用numpy和R的用户会熟悉熊猫。
这是解决熊猫问题的方法:
>>> import pandas as pd
>>> raw = [{'state': '1', 'city': 'a'},
{'state': '1', 'city': 'b'},
{'state': '2', 'city': 'c'},
{'state': '2', 'city': 'd'},
{'state': '3', 'city': 'e'}]
>>> df = pd.DataFrame(raw) # magic !
>>> df
city state
0 a 1
1 b 1
2 c 2
3 d 2
4 e 3
>>> grouped = df.groupby('state')['city']
>>> grouped
<pandas.core.groupby.SeriesGroupBy object at 0x05F22110>
>>> listed = grouped.apply(list)
>>> listed
state
1 [a, b]
2 [c, d]
3 [e]
Name: city, dtype: object
>>> listed.to_dict() # magic again !
{'1': ['a', 'b'], '3': ['e'], '2': ['c', 'd']}
更复杂的示例,包括此处的grouped.apply(custom_fct)
:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.