2008/06/16

Pythonのソートについて: sort()とsorted()


Photo by Fort Photo, "Fountains of Light"
自分のためにメモ。pythonでソートを行おうとする場合、リストに組み込まれている関数list.sort()と、単独で使える関数sorted()の2つがある。基本的に取る引数は同じなので機能自体はあまり変わりないのだが、以下の2点が異なる。
  • sort()関数は返り値を出さずに、リストの本体自体を変更してしまう。これはreverse()関数と同じ。
  • sort()関数はソートの対象がリストであるのに対し、sorted()関数は対象がイテレータとなる。
試しにpython上で確認してみる。
>>> x = [1,6,3,8,4]
>>> y = [1,6,3,8,4]
>>> y.sort()
>>> y
[1, 3, 4, 6, 8]
>>> sorted(x)
[1, 3, 4, 6, 8]
きちんと両方ともソートが行われているようだ。それでは次に引数cmp, key, reverseについて調べてみる。
"cmp"キーワードには、二つのオブジェクトxとyがあったときに、どちらが大きいのかを示す関数、あるいはλ式を指定する。普通はそのままで十分であるが、比較用のオブジェクトがちょっと特殊な場合に役立つ。
もしcmpキーワードを指定しなければならないような場合、通常ならばλ式の中にcmp(x,y)関数を導入する。cmp(x,y)関数はxとyを比較して、指定すべき適切な値を返してくれる関数。これを導入すれば、
あれ?cmpキーワードってx < yの場合にはx - yを指定すればいいんだっけ?それともy - xだっけ?』とかいうような余計な心配をしなくて済む。
"key"キーワードには、比較対象とするオブジェクトはどのオブジェクトであるのかを示す関数、あるいはλ式を指定する。何も指定しなかった場合、配列やタプルであれば一番目(インデックスが0)のオブジェクトが比較対象であると判別されるようだ。
"reverse"キーワードはソート結果が昇順であるか降順であるかを指定する。Trueを指定すると降順になる。sort()してからreverse()などのように2つメソッドをくっつける必要はない。
それでは今までの流れを踏まえて試しに簡単なプログラムを組んでみる。辞書には{"名前":"点数"}などのように名前と点数のペアが保存されている。これを点数が高い順に並び替えるというプログラムは以下のように記述できる。
>>> dic = {"Hanako":"50", "Taroh":"80", "Ichiroh":"30", "Yoshio":"60"}
>>> sorted(dic.items(), cmp=lambda x, y:cmp(int(x), int(y)), key=lambda x:x[1], reverse=True)
[('Taroh', '80'), ('Yoshio', '60'), ('Hanako', '50'), ('Ichiroh', '30')]
ちなみに上の式は以下のようにも記述できる(というかそっちのほうが普通)。
>>> sorted(dic.items(), key=lambda x:int(x[1]), reverse=True)
[('Taroh', '80'), ('Yoshio', '60'), ('Hanako', '50'), ('Ichiroh', '30')]
6/30 追記
最初のソート部分が間違っていたので修正しました。以前の書き方だとxとyは同一の配列オブジェクトを参照していることになりますね。すいません。

5 件のコメント:

匿名 さんのコメント...

>>> x = [1,6,3,8,4]
>>> y = x
>>> y.sort()
これだとyをソートした時点でxもソートされますよ。

rezoo さんのコメント...

あわわ、本当でした。今気づいて慌てて修正しました。
いやぁ申し訳ないです。

匿名 さんのコメント...

reservedってなってるところがあります。

shinriyo さんのコメント...

reversed=True
がまだそのままですね。

Masaki Saito さんのコメント...

今更ですが修正しました.thx