Pyhonで辞書のソート

beanz (2008年11月14日 13:52) | コメント(0) | トラックバック(0)

Pyhonでリストをソートしたい時はリストのsortメソッドか組み込みのsorted()関数がある。
どちらも特に難しくない。例えば

flower = ["Sunflower","Morning glory","Tulip","Violet","Cosmos","Rose"]

こんなリストがありそれを

flower.sort()

とすると'flower'の中身は

['Cosmos', 'Morning glory', 'Rose', 'Sunflower', 'Tulip', 'Violet']

こうなっている。逆順にしたい時は

flower.sort(reverse=True)

とすればいい、中身は

['Violet', 'Tulip', 'Sunflower', 'Rose', 'Morning glory', 'Cosmos']

こうなる。あと、例えば文字数でソートしたい時は

flower.sort(key=len)

とすれば、中身は

['Rose', 'Tulip', 'Violet', 'Cosmos', 'Sunflower', 'Morning glory']

と、文字数の少ない順番でソートされている。もちろん

flower.sort(key=len, reverse=True)

も出来る。

ちなみにsortメソッドが使えるのはリストだけだ。他のシーケンス、例えば文字列やタプル等は書き換えが出来ない型なので自身を書き換えてしまうsortのようなメソッドは用意されていない。
この場合はsorted関数を使う事で対応できる。ただし戻り値が(文字列もタプルも)リストになってしまうので必要であればそれぞれ型を戻してやる必要がある。
文字列をソートする意味があるかどうかはともかく

m = 'ALFKSUNRWUSsdgskjdfgsADAdg'

こんな意味不明な文字列があったとしてそれに

sorted(m)

としてやると

['A', 'A', 'A', 'D', 'F', 'K', 'L', 'N', 'R', 'S', 'S', 'U', 'U', 'W', 'd', 'd', 'd', 'f', 'g', 'g', 'g', 'j', 'k', 's', 's', 's']

なんてリストが返ってくる。文字列に戻すには文字列用のjoinメソッドを使えばいい。
一気にやってしまいたい場合は

"".join(sorted(m))

これで'AAADFKLNRSSUUWdddfgggjksss'なんて文字列が返ってくる。

では、辞書をソートしたい時はどうすればいいだろう?

辞書自身をソートする事は出来ない。これは先ほどの文字列やタプルの時のような"書き換えが出来ないから"ではなく辞書には順番という概念が無いからだ。ちなみに書き換えは幾らでも出来る。
辞書には順番が無いが辞書の内容をある規則で並べ替えて書き出したい時は当然あるだろう。
その時にキーと値、どちらを対象に並べ替えたいかによってその後の処理も変わってくる。

まずはキーを基に並べ替えてみる。これはさほど難しくない。
例えば名前と年齢から構成される辞書で

smap = {'nakai': 36, 'kimura': 35, 'katori': 31, 'kusanagi': 34, 'inagaki': 34}

と、こんなのがあるとする。これをキーである名前を基にソートし、出力するには

for i in sorted(smap):
    print i + " => " + str(smap[i])

これでいい。これで

inagaki => 34
katori => 31
kimura => 35
kusanagi => 34
nakai => 36

こんな出力が得られる。

for i in sorted(smap,key=len):
    print i + " => " + str(smap[i])

こうすれば

nakai => 36
kimura => 35
katori => 31
inagaki => 34
kusanagi => 34

こうなる。
では、値(この場合は年齢)を基にソートしたい時はどうすればいいか?
辞書では値のリストを得るためのvaluesメソッドがあるが単純に

for i in sorted(smap.values()):

こうしただけでは駄目。こうすると値(年齢)がソートされて返ってくるが、その値からキー(誰の?)を導きだす事は出来ない。ただ単に数値が並んでいるだけだ。
じゃあ、どうしよう?
辞書にはキーと値をタプルとして返してくれるitemsメソッドがある。

smap.items()

を実行すると

[('nakai', 36), ('kimura', 35), ('inagaki', 34), ('katori', 31), ('kusanagi', 34)]

と返ってくる。このタプルに対してsorted関数を呼び出してみると

sorted(smap.items())

次の値が返ってくる

[('inagaki', 34), ('katori', 31), ('kimura', 35), ('kusanagi', 34), ('nakai', 36)]

ソートはされているがキー(ここではキーというよりタプルの中の最初の要素)を基にしている。
では次にsorted関数のオプション引数であるkeyを使ってみる。
このオプションで"何を基にソートするか"を指定できる。ここではタプルの2番目の要素でソートしてほしいので

sorted(smap.items(), key=lambda i: i[1])

こんな感じだ。これで

[('katori', 31), ('inagaki', 34), ('kusanagi', 34), ('kimura', 35), ('nakai', 36)]

が得られた。当然

sorted(smap.items(), key=lambda i: i[1], reverse=True)

これも問題なく

[('nakai', 36), ('kimura', 35), ('inagaki', 34), ('kusanagi', 34), ('katori', 31)]

逆順になっている。
出力まで一気にやってしまうと

for i in sorted(smap.items(), key=lambda i: i[1]):
    print i[0] + " => " + str(i[1])

これで

katori => 31
inagaki => 34
kusanagi => 34
kimura => 35
nakai => 36

見事に値でソートされた。
それにタプルのリストをソートした時はタプルの最初の要素でソートされるという事も分かった。
なら、smap.items()を実行した時にキーと値を入れ替えたタプルが生成されればいいという事になる。
そうすればいちいちsorted関数の中でkeyを指定しなくてもすむ。
じゃあ、それを作ってみよう。リスト内包表記を使う。

for i in sorted([(smap[i], i) for i in smap]):
    print i[1] + " => " + str(i[0])

出力は

katori => 31
inagaki => 34
kusanagi => 34
kimura => 35
nakai => 36

問題無しだ。ソートされて返ってくるリストの中身はタプルだがそのタプルの中の順番が最初の例とは逆になっている。
なので出力するときはタプルの添字に注意。

それにしてもPythonのリスト内包表記ってのはすごいなあ。これがあるからPythonを使うって人もいるんじゃないだろうか。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/21

コメントする