目录
- 问题
- 解决方案
- 讨论
问题
如果有一系列的字典或对象实例,我们想根据某个特定的字段来分组迭代数据。
解决方案
假设有如下字典列表:
rows = [
{'address': '5412 N CLARK', 'date': '07/01/2012'},
{'address': '5148 N CLARK', 'date': '07/04/2012'},
{'address': '5800 E 58TH', 'date': '07/02/2012'},
{'address': '2122 N CLARK', 'date': '07/03/2012'},
{'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},
{'address': '1060 W ADDISON', 'date': '07/02/2012'},
{'address': '4801 N BROADWAY', 'date': '07/01/2012'},
{'address': '1039 W GRANVILLE', 'date': '07/04/2012'}
]
在对上述数据进行分组时,使用 itertools.groupby()
函数非常有用。
假设我们想以日期为分组的方式迭代显示数据,首先通过 operator.itemgetter()
函数进行排序,然后通过 itertools.groupby()
进行分组。
from operator import itemgetter
from itertools import groupby
rows.sort(key=itemgetter('date'))
for date, items in groupby(rows, key=itemgetter('date')):
print(date)
for i in items:
print(' ', i)
产生结果如下:
讨论
函数 groupby()
通过扫描序列对相同值或者 key 指定的值进行分组。原理上,groupby()
创建了一个迭代器,每次迭代时返回一个值以及一个子迭代器,这个子迭代器会产生所有在该分组内具有该值的项。
需要注意的是,必须首先对字段根据需求进行排序,因为 groupby()
只能检查连续的项,不首先排序的话,将无法按照要求的方式进行分组。而反过来讲,如果只需要简单的按照日期将数据进行分组,那么使用 defaultdict()
即可:
from collections import defaultdict
rows_by_date = defaultdict(list)
for row in rows:
rows_by_date[row['date']].append(row)
print(rows_by_date)
结果:
defaultdict(<class 'list'>, {
'07/01/2012': [{'address': '5412 N CLARK', 'date': '07/01/2012'}, {'address': '4801 N BROADWAY', 'date': '07/01/2012'}],
'07/04/2012': [{'address': '5148 N CLARK', 'date': '07/04/2012'}, {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}],
'07/02/2012': [{'address': '5800 E 58TH', 'date': '07/02/2012'}, {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}, {'address': '1060 W ADDISON', 'date': '07/02/2012'}],
'07/03/2012': [{'address': '2122 N CLARK', 'date': '07/03/2012'}]})