itertools.groupby の使いどころが今ひとつ分からない。
リストを分割したいことがある。
[1,4,3,2,1,3] -> [[1, 1], [2], [3, 3], [4]]
みたいな感じで「同じものでまとめたリストのリストをつくる」
っていう処理をすることがチョコチョコあるので下記みたいなので対応してた。
def group_by_key(iterable, key_fn=hash): # デフォルトだとhash関数 """ key で渡した関数の結果ごとにリストを分割する """ result_dict = {} for i in iterable: # 引数で受け取った関数を適用した結果を辞書のキーとして使う dict_key = key_fn(i) if result_dict.get(dict_key, None) is not None: # すでに仲間があったらそのリストに追加 result_dict[dict_key].append(i) else: # キーがまだ存在しない場合は要素1つのリストを入れる result_dict[dict_key] = [i, ] # 辞書から値の束だけ取り出して返す return result_dict.values()
でもitertools.groupbyの説明を読む限り同じようなことをしている模様。
ただ、ソートしとかないとうまくグループにしてくれなかったり、
戻り値の形がけっこう変だったり。なんでこんな風になってるのか。
itertools.groupbyもこう書くと上記のと同じような結果がもらえる
def itertool_groupby(objs, key_fn): """ itertools.groupby で出す場合 """ # ソートしとかないとうまくグループにしてくれないのでsort objs.sort(key=key_fn) # [(id, gen),(id, gen)..] こんな戻り値なので ret_group_by = itertools.groupby(objs, key_fn) # 2個目の要素のジェネレータをとり出してリストにキャストする # [(id, gen),(id, gen)..] -> [list,list..] return map(lambda x:list(x[1]), ret_group_by)