2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonでDynamoDBからのクエリ結果を処理する場合の便利集(内包表記、無名関数によるソート)

Posted at

はじめに

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などの試験時に処理したいケースが多いです。

  • 辞書のリストから特定の条件に当てはまる辞書(オブジェクト)を取り出したい
    • 例:タイムスタンプに対して期限を超えたオブジェクトだけを取り出す
  • 辞書のリストを特定のキーごとに並べ替える
    • 例:オブジェクトの特定のキーで並び替え、pytestassertしたい場合
  • オブジェクト内の特定のキーを一括削除したい
    • 例:IDなど特定のプロパティがUUID4などで決定しており、pytestで除外してassertしたい場合

上記のようなケースに対して、内包表記や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で処理する場合、辞書のリストを扱うケースが多いため、チーム内で記載方法は統一しておくと便利かもしれません。

他にも良い記載方法があれば、コメントで教えていただけるとありがたいです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?