モブプロな人たちのブログ

横浜で Web サービス開発しているエンジニアの日記です。Python 大好き Flask 大好き。たまに SpriteKit でゲーム開発も。

Python の itertools.groupby の使いどころが何となく分かった話

こんにちは、kaorr です。

一人アドベントカレンダー1日目です。

はじめに

itertools.groupby とは↓のことです。

10.1. itertools — 効率的なループ実行のためのイテレータ生成関数 — Python 3.6.3 ドキュメント

過去に一度だけ役立つ場面があったので、改めてまとめてみます。

f:id:kaorr_mob:20171201222907j:plain

利用場面

単純ですが「SQL でクエリ投げることが出来ない状況で、何か集計っぽいことしたい」場面になります。

SQL でグリグリ出来る環境があるのに、ムダに Python のレイヤーでグリグリしてたら、「なんでわざわざ Python 使ってんだよ!!」と罵倒されることになるので注意が必要です・・・!

前提とサンプルデータ

  • チーム対抗でゲームを行い、チーム毎の獲得賞金をメンバで分配したい。

  • 分配する際の基準は、メンバ毎の貢献ポイントとする。

  • 各メンバが、チーム内で何割貢献し、結果としていくら賞金がもらえるかを一覧で出力したい。

  • チーム毎の獲得賞金。

チーム名 賞金
山田チーム 2,500,000
田中チーム 400,000
鈴木チーム 3,200,000
  • メンバ毎の貢献ポイント。
チーム名 メンバ名 貢献ポイント
山田チーム 山田 10
山田チーム 吉田 20
山田チーム 武田 30
田中チーム 田中 5
田中チーム 田辺 2
鈴木チーム 鈴木 80
  • 最終的に欲しいデータ。
チーム名 賞金 メンバ名 貢献ポイント 貢献割合 取り分
山田チーム 2,500,000 山田 10 16.67% 416,750
山田チーム 2,500,000 吉田 20 33.33% 833,250
山田チーム 2,500,000 武田 30 50.0% 1,250,000
田中チーム 400,000 田中 5 71.43% 285,720
田中チーム 400,000 田辺 2 28.57% 114,280
鈴木チーム 3,200,000 鈴木 80 100.0% 3,200,000

コード全体

こんな感じです。

gistff05eed81642e4827729b99264c7c0bf

補足

  • グループ化されたデータの持ち方

以下の出力結果を見ると分かりやすいと思いますが、key にはキーとした値、group にはキーによってグループ化された値がイテレータで格納されます。

なので、二回以上読み込みたいときは、一度リストなどに変換しておくと楽です。

gistb69744a0a92654b0553b774850b56a82

  • groupby する前にはソートが必要

公式ドキュメントにも書いてありますが、groupby は key の値を順次読んでいき、それが変わったタイミングでグループを判断するため、key とする値でソートされていることが前提になります。

感想

はじめに「過去に一度だけ」とだけ書きましたが、よくよく考えると最近になって、SQL でクエリを投げられないタスクが増えてきていました。

改めて整理して頭の片隅に置いておくと、また何か役立つ場面がきそうな気がします!

f:id:kaorr_mob:20171201224438j:plain