はじめに
DynamoDBに入ったデータをboto3のqueryすると、こんな感じでItemsにプロパティが格納されます。
[
{
"id": "id_01",
"val": 10,
"test": "test_72095"
},
{
"id": "id_02",
"val": 20,
"test": "test_64051"
},
{
"id": "id_03",
"val": 30,
"test": "test_84762"
}
]
いわゆる辞書のリストと呼ばれる形式ですが、以下の場合は割と処理が面倒になります。
個人的にはpytest
などの試験時に処理したいケースが多いです。
- 辞書のリストから特定の条件に当てはまる辞書(オブジェクト)を取り出したい
- 例:タイムスタンプに対して期限を超えたオブジェクトだけを取り出す
- 辞書のリストを特定のキーごとに並べ替える
- 例:オブジェクトの特定のキーで並び替え、
pytest
でassert
したい場合
- 例:オブジェクトの特定のキーで並び替え、
- オブジェクト内の特定のキーを一括削除したい
- 例:IDなど特定のプロパティがUUID4などで決定しており、
pytest
で除外してassert
したい場合
- 例:IDなど特定のプロパティがUUID4などで決定しており、
上記のようなケースに対して、内包表記やLambda式(無名関数)などを使って処理する方法をまとめます。
検索:特定の条件に当てはまるオブジェクトを取り出したい
forを使って回すこともできますが、内包表記を使ってワンライナーで記載します。
ここではval
が10より大きい場合のアイテムだけを抽出します。
(DynamoDBからクエリしたItemsは、変数items
に格納しています)
abstracted_items = [d for d in items if d['val'] > 10]
print(abstracted_items)
# [{'id': 'id_02', 'val': 20, 'test': 'test_64051'}, {'id': 'id_03', 'val': 30, 'test': 'test_84762'}]
ソート:オブジェクトの特定のキーで並び替えたい
次に辞書のリストをソートするケースです。
辞書はオブジェクトの大小比較がサポートされていないため、辞書のリストに対してそのままsorted
を使うとエラーとなります。
sorted_items = sorted(items)
> TypeError: '<' not supported between instances of 'dict' and 'dict'
そこで、辞書のリストに対して特定のキーで並び替えたい場合は、sort
メソッドやsorted
関数にkey
を指定します。
注意点としては、key
には関数を指定する必要があります。
list.sort() と sorted() には key パラメータがあります。 これは比較を行う前にリストの各要素に対して呼び出される関数 (または呼び出し可能オブジェクト) を指定するパラメータです。
そのため、辞書内のキーの値を取り出す関数を作成する必要がありますが、このような場合はLambda式(無名関数)を使うと簡単に書けます。
以下は、test
のキー値でソートしています。
sorted_items = sorted(items, key=lambda x:x['test'])
print(sorted_items)
# [{'id': 'id_02', 'val': 20, 'test': 'test_64051'}, {'id': 'id_01', 'val': 10, 'test': 'test_72095'}, {'id': 'id_03', 'val': 30, 'test': 'test_84762'}]
削除:オブジェクトの特定のキーを一括削除したい
最後に、辞書の特定のキーを削除したい場合を考えます。
リストの内包表記の中に辞書の内包表記を書くことで、対応しました。
今回はtest
キーを削除しています。
deleted_items = [{k: v for k, v in d.items() if not k == 'test'} for d in items]
print(deleted_items)
# [{'id': 'id_01', 'val': 10}, {'id': 'id_02', 'val': 20}, {'id': 'id_03', 'val': 30}]
一応ワンライナーでは書けますが、分かりづらいかもしれません。
ワンライナーでの拘りがなければ、forや関数化した方が可読性は上がると思います。
まとめ
DynamoDBをPythonで処理する場合、辞書のリストを扱うケースが多いため、チーム内で記載方法は統一しておくと便利かもしれません。
他にも良い記載方法があれば、コメントで教えていただけるとありがたいです。