secretbase.log

.NET/C#/Pythonなど

Python の辞書に含まれる最大値のKeyを求めるクールな実装

下記のような辞書型があり、辞書の値の最大値を持つキーを取得したい。
例えば、下記のような辞書だ。

d = {'a': 1, 'b': 2, 'c': 3}

上記例では、 3 が最大値。よって、 c を得たい。
ここで if文のような条件分岐をつかった実装は クールではないのは容易に想像がつく。

ちなみに、最大値は、組み込み関数の max で取得できる。

>>> max(d.values())
3

とやると、3 を取得することはできるが、そのキーはどうすれば取得できるだろう。

Python ではどのような実装がクールなのだろうか、とつぶやいたら RT され 一瞬で Reply をいくつかいただけた。
ありがたく、ご紹介させて頂く。
(一応、Python 2.7.5 を想定したのだが、明示しなかったので py3向けの回答もあったのかもしれない)


1. タプルにして最大値を求める実装

>>> max([(v,k) for k,v in d.items()])[1]
'c'
>>> max((v,k) for (k,v) in d.items())[1]
'c'

d.items() でタプルのペアを含むリストが取得できる。

>>> d.items()
[('a', 1), ('c', 3), ('b', 2)]

最初の例は、リスト内包表記を用いリストにしそれを渡している。
2番目の例は、引数として複数のタプルを渡している。

いずれの例も、for文で内部のタプルを取り出し v (value)の最大値を求める。
最後の [1] を k を意味している。

max の仕様として、リスト(のようなiteratable)または複数の引数を受け付けるという仕様。Docstring を読む。

max(iterable[, key=func]) -> value
max(a, b, c, ...[, key=func]) -> value

なお、Python 2系なら items の変わりに iteritems を使うと気持ち効率が良いらしい(未確認)




2. max のオプション引数 key を用いる実装 (itemgetter)

>>> from operator import itemgetter
>>> max(d.items(), key=itemgetter(1))[0]
'c'

ここで maxの仕様 に目を通すと以下のような記載がある。

オプションの key 引数には list.sort() で使われるのと同じような 1 引数の順序付け関数を指定します。

Python 2.5以降で使える。 key= で関数を渡す。これを用いた実装だ。ここでは itemgetter() を使っている。

operator モジュールで提供されている。

>>> itemgetter(1)(("c",3))
>>> 3

ここでは、上記のように 1番目のタプルの要素を渡す関数となっている。



3. max のオプション引数 key を用いる実装 (lambda)

>>> max(d.items(), key=lambda x:x[1])[0]
'c'

lambdaを用い 配列要素の1番目を返却する無名関数を作成し、オプション引数に渡す実装。
これが一番シンプルな実装な気もする。