質問:
辞書またはインスタンスのシーケンスがあり、日付などの特定のフィールドごとにグループ化してそれらを反復処理したいとします。
解決:
itertools.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'},
{
'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
]
ここで、日付ごとにグループ化されたデータのチャンクを反復処理するとします。これを行うには、まず指定したフィールド (この場合は日付) で並べ替えてから、 itertools.groupby() 関数を呼び出す必要があります。
from operator import itemgetter from itertools import groupby
# Sort by the desired field first
rows.sort(key=itemgetter('date'))
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('date')):
print(date) for i in items:
print(' ', i)
操作結果:
07/01/2012
{
'date': '07/01/2012', 'address': '5412 N CLARK'}
{
'date': '07/01/2012', 'address': '4801 N BROADWAY'}
07/02/2012
{
'date': '07/02/2012', 'address': '5800 E 58TH'}
{
'date': '07/02/2012', 'address': '5645 N RAVENSWOOD'}
{
'date': '07/02/2012', 'address': '1060 W ADDISON'}
07/03/2012
{
'date': '07/03/2012', 'address': '2122 N CLARK'}
07/04/2012
{
'date': '07/04/2012', 'address': '5148 N CLARK'}
{
'date': '07/04/2012', 'address': '1039 W GRANVILLE'}
groupby() 関数はシーケンス全体をスキャンし、同じ連続値 (または指定されたキー関数によって返された同じ値) を持つ要素のシーケンスを見つけます。各反復で、要素値がすべて上記の値と等しいグループ内のすべてのオブジェクトを生成できる値とイテレータ オブジェクトを返します。
非常に重要な準備ステップは、指定されたフィールドに従ってデータを並べ替えることです。groupby() は連続する要素のみをチェックするため、事前に並べ替えが行われていない場合、グループ化関数は望ましい結果を取得しません。
日付フィールドに基づいてデータを大規模なデータ構造にグループ化し、ランダム アクセスを許可するだけの場合は、defaultdict() を使用して複数値の辞書を構築することをお勧めします。
from collections import defaultdict rows_by_date = defaultdict(list) for row in rows:
rows_by_date[row['date']].append(row)
指定した日付ごとに対応するレコードに簡単にアクセスできます。
>>> for r in rows_by_date['07/01/2012']:
... print(r)
...
{
'date': '07/01/2012', 'address': '5412 N CLARK'}
{
'date': '07/01/2012', 'address': '4801 N BROADWAY'}
>>>
メモリ使用量をあまり気にしない場合は、このメソッドは、最初に並べ替えてから groupby() 関数を繰り返すよりも高速に実行されます。