from operator import itemgetter
from itertools import groupby
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'}
]
# 对rows按date字段排序
rows.sort(key=itemgetter('date'))
group_date = groupby(rows,key=itemgetter('date'))
for date,items in group_date:
print(date,items)
for i in items:
print('',i)
运行结果:
07/01/2012 <itertools._grouper object at 0x0000020385E3E5C0>
{'address': '5412 N CLARK', 'date': '07/01/2012'}
{'address': '4801 N BROADWAY', 'date': '07/01/2012'}
07/02/2012 <itertools._grouper object at 0x0000020385E3EB38>
{'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 <itertools._grouper object at 0x0000020385E3E5C0>
{'address': '2122 N CLARK', 'date': '07/03/2012'}
07/04/2012 <itertools._grouper object at 0x0000020385E3EB38>
{'address': '5148 N CLARK', 'date': '07/04/2012'}
groupby() 函数扫描整个序列并且查找连续相同值 (或者根据指定 key 函数返回值相同) 的元素序列。在每次迭代的时候,它会返回一个值和一个迭代器对象,这个迭代器对象可以生成元素值全部等于上面那个值的组中所有对象。一个非常重要的准备步骤是要根据指定的字段将数据排序。因为 groupby() 仅仅检查连续的元素,如果事先并没有排序完成的话,分组函数将得不到想要的结果。
以上代码operator中itemgetter还支持对字典多个键对应的值排序,优先传入的键优先按对应值排序,后传入的键在原排序的基础上对对应的值再排序,还有operator中还提供了attrgetter方法,结合内置的sorted()函数(有一个关键字参数 key ,可以传入一个 callable 对象给它),可以排序不支持原生比较的对象。试例如下:
class User:
def __init__(self, user_id):
self.user_id = user_id
def __repr__(self):
return 'User({})'.format(self.user_id)
users = [User(23), User(3), User(99)]
print(users)
print(sorted(users, key=lambda u: u.user_id))
print(sorted(users,key=attrgetter('user_id')))
运行结果:
[User(23), User(3), User(99)]
[User(3), User(23), User(99)]
[User(3), User(23), User(99)]
以上两种排序推荐使用attrgetter()函数,因为该函数运行快点,并且还能同时允许多个字段进行比较。