2013年11月9日土曜日

RubyのUFO演算子を利用したソート処理について

今日、長年?の疑問がひとつ解消したが、また忘れそうなのでメモ。
Rubyでイテレータを使ったソートのコード。
例えば、以下のコードは文字列配列arrayの中身をアルファベット順にソートする。

array=%w(R U B Y)
sorted=array.sort{|a,b|
a <=>b
}

これ、実はよく分かっていなくて、ずっと引っかかっていた。
イテレータなのだが、よく処理を渡すと説明がある。

以下疑問点
・処理を渡す引数は何処?|a,b|のaとbに何か渡すの?
・突然出てくる、a<=>bの箇所が不明。UFO演算子でA < Bならば負の数を返し、
A > Bならば正の数を返し、AとBが等しければ0を返す。は分かるが、その戻り値は何処に返っているの?
・a<=>bでアルファベット順に並べるとあるので、これ自体がアルファベット順に並べる命令?とすると、数字を並べるのは1<=>2とか??
・そもそも、ソート処理にブロックを渡しているのが違和感がある。
・イテレーターってループ処理のことじゃなかったっけ??

今となってはかなりアホな疑問なのだが、ついさっきまで理解できていなかった。
(なので、定型句としての理解だった)

a<=>bというのは、上記の通り2つの値を比較するもの。
数字や文字コードなどの比較を行い、その大小に応じて、-1,0,1を返す。
http://docs.ruby-lang.org/ja/search/query:%EF%BC%9C%EF%BC%9D%EF%BC%9E/

で、これ、ソートの判定条件をセットしているんです。

っといっても、鈍感な私はピンと来なかったわけです。
で、こいつを分解していきます。

sorted=array.sort{<ソートする判定条件>}
これが最初の疑問処理を渡す引数は何処?の答え。
では、その中身がどういう動きをしているのか書いてみる。
簡単なバブルソートの例ですが。

array=%w(R U B Y)
cnt=array.size-1
for i in 0..cnt
  for j in 0..cnt -i -1
    case array[j]<=>array[j+1] #ここ
    when +1 then
      swap=array[j]
      array[j]=array[j+1]
      array[j+1]=swap
    end
  end
end

2番目の疑問。
こいつ自体は、ソート時の判定処理に組み込まれる。
この例では、+1の時しか役に立っていないが、+1,0,-1を返すことを期待されている。
ここまで来ると、3つ目の疑問が自ずと解消される。
これは、
|a,b|
A~Bという意味ではなく、単なる変数で、array[j]とarray[j+1]がセットされる。
なので、別に|z,a|でも良い。
そして、次の
a<=>bが結果的に
array[j]<=>array[j+1]
となり、上記のcase文判定条件となる。

4つ目の疑問。
これはソート条件をプラグインで差し替えることを目的としている。
例えば、
a<=>b
の箇所を
a.length<=>b.length
にすると、結果的に
array[j].length<=>array[j+1].length
となり、文字列長での並び替えとなる。

処理を渡すと言われると、上記のコードを丸々変数か何かに入れて渡すとかをイメージするので、訳が分からなかったが、
上記コードが遮蔽されていて、判定条件部分を渡すのなら合点が行った次第。


ちなみに、UFO演算子は宇宙船演算子が正しい??






0 件のコメント:

コメントを投稿