Python进阶编程:编写更高效、优雅的Python代码
上QQ阅读APP看书,第一时间看更新

3.3.3 记录分组

在实际操作字典或实例序列中的记录时,我们需要实现分组迭代访问,如根据某个特定的字段比如date来分组迭代访问。

对于数据分组操作来说,itertools.groupby()函数非常实用。假设我们已经有下列的字典列表:


done_record = [
    {'done': 'read book', 'date': '07/01/2020'},
    {'done': 'work', 'date': '07/04/2020'},
    {'done': 'family chat', 'date': '07/02/2020'},
    {'done': 'run', 'date': '07/03/2020'},
    {'done': 'sport', 'date': '07/02/2020'},
    {'done': 'read 20 pages', 'date': '07/02/2020'},
    {'done': 'run 5km', 'date': '07/01/2020'},
    {'done': 'sport 2 hours', 'date': '07/04/2020'},
]

需要在按date分组后的数据块上进行迭代。首先需要按照指定的字段(比如date)排序,然后调用itertools.groupby()函数,代码如下:


from operator import itemgetter
from itertools import groupby

done_record = [
    {'done': 'read book', 'date': '07/01/2020'},
    {'done': 'work', 'date': '07/04/2020'},
    {'done': 'family chat', 'date': '07/02/2020'},
    {'done': 'run', 'date': '07/03/2020'},
    {'done': 'sport', 'date': '07/02/2020'},
    {'done': 'read 20 pages', 'date': '07/02/2020'},
    {'done': 'run 5km', 'date': '07/01/2020'},
    {'done': 'sport 2 hours', 'date': '07/04/2020'},
]

# Sort by the desired field first
done_record.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(done_record, key=itemgetter('date')):
    print(date)
    for i in items:
        print(' ', i)

groupby()函数扫描整个序列并且查找连续相同值(或者根据指定key函数返回值相同的元素序列)。

在每次迭代的时候,groupby()函数会返回一个值和一个迭代器对象,该迭代器对象可以生成元素值全部等于上面元素序列中元素值的对象。

一个非常重要的准备步骤是要根据指定的字段对数据进行排序。由于groupby()函数仅仅检查连续的元素,如果事先没有对元素完成排序,我们将得不到想要的结果。

如果仅仅只是想根据date字段将数据分组到一个大的数据结构中,并且允许随机访问,那么最好使用defaultdict()函数来构建一个多值字典,示例如下:


from collections import defaultdict
record_by_date = defaultdict(list)
for record in done_record:
    record_by_date[record['date']].append(record)

这样,我们就可以很轻松地对每个指定日期访问对应的记录,代码如下:


for record in record_by_date['07/01/2012']:
    print(record)

在该示例中,没有必要先将记录排序。如果对内存占用不是很关心,这种方式会比先排序,然后再通过groupby()函数迭代的方式运行得快一些。