[英]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.