Pythonのsortメソッド

beanz (2008年10月28日 01:27) | コメント(0) | トラックバック(0)

Rubyだと以下のような文が書ける

list1 = %w/taro hanako ryota hiroshi kotaro haruki kiyotaka jun/
list2 = list1.sort

これはlist1の配列を並べ替えた新規の配列list2を作成している。
list1は元の順番のまま何の変更も加えられていない。
さらに以下のような文も書ける

list1 = %w/taro hanako ryota hiroshi kotaro haruki kiyotaka jun/
list2 = list1.sort!

上の文との違いはsortの後ろに感嘆符(!)が付いているかいないかだけだが感嘆符がついた方はlist1自身を並べ替えてしまう。
つまりはlist1とlist2は同じ順番で並んだ全く同じ配列となる。

Perlでも次のように書ける

my @list1 = qw/taro hanako ryota hiroshi kotaro haruki kiyotaka jun/;
my @list2 = sort @list1

@list1自身を書き換えたければ

@list1 = sort @list1

と再代入すればいい。

Rubyの"Array.sort"、"Array.sort!"、Perlの"sort Array関数"はそれぞれ要素を並べ替えて返してくれるから、例えば

Perlの場合

@list2 = map {$_." Hello!"} sort @list1

Rubyの場合

list2 = list1.sort.map{|i|"#{i} Hello!"}

みたいな、配列を並べ替えつつそれぞれの要素に文字列を足す、そして新しい配列を作る。
当然文字列を足すだけじゃなく例えば数値であれば乗算したり数値用の演算が出来るし、もっと複雑な関数(メソッド)も値を返すものであれば処理の結果で新しい配列を作る事が出来る。

ところがPythonの場合はまたしてもうまくいかない。
Pythonの文字列やリストにもsortというメソッドがあるがこのメソッドは値を返さず、自身を書き換えるいわゆる破壊的メソッドだ。
Rubyの場合それでも値を返していたがPythonのそれはNoneしか返してくれないので例えば

list1 = ["taro", "hanako", "ryota", "hiroshi", "kotaro", "haruki", "kiyotaka", "jun"]
list2 = list1.sort()

と、こんなコードを書いてもlist2には何も入っていない。
さらにもとのリストを書き換えるつもりが無くてもlist1はソート済みのリストになっている。
RubyやPerlになれてるとPythonの挙動にはことごとく裏切られる。
reverseメソッドもそうだ(値を返さず自身を書き換えてしまう)。

なのでPythonで書く時は、まず

  1. リストをコピーして新規のリストを作成する
  2. コピーしたリストのソートメソッドを呼び出しリスト自身を書き換える
  3. そしてforループに渡すなりその後の処理を呼び出す。

みたいな面倒くさい事をしていたが、最近sorted関数やreversed関数なるものがあるという事が分かった。
これは自身を書き換える事なく新規の値を返してくれる、Perlのsort関数みたいなものだ。

"Pythonチュートリアル"という本に書いてあった。
上の文は以下のように書けるし、

list2 = sorted(list1)

当然forループに渡したり、リスト内包表記にも使える。

list2 = [i + " Hello!" for i in sorted(list1)]

そっか、こんな事が出来たんだ。
以前勉強した"はじめてのPython"にはこんな事は書いてなかったような・・。
もうさすがに書いてある事が古くなったんだろうなあ。

カテゴリ:

トラックバック(0)

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

コメントする