a = Array.new(2) b = Array.new(2) for i in 0..1 b[i] = a for j in 0..1 b[i][j] = i end endのように書くと,
のような構造が作られて,見かけは二次元配列だがそれぞれの要素が独立に変更できないものになるのに対して,
b = Array.new(2) for i in 0..1 b[i] = Array.new(2) for j in 0..1 b[i][j] = i end end bのように書くと,
のようになって,要素を独立に変更できるようになるというのがポイントになります.長々と説明をしたのは,
def make2d(h,w) b=Array.new(h) a=make1d(w) for i in 0..(h-1) b[i]=a end b endでは駄目で,なぜ,
def make2d(h,w) b=Array.new(h) for i in 0..(h-1) b[i]=make1d(w) end b endと書かなくてはいけないかということを分かってもらうためですね.
def median(x,y,z) if x>y if y>z y else if x>z z else x end end else if x>z x else if y>z z else y end end end endチェックをするには6通りのすべての組み合わせをおこなう.
irb(main):026:0* median(1,2,3) => 2 irb(main):027:0> median(2,3,1) => 2 irb(main):028:0> median(3,2,1) => 2 irb(main):029:0> median(1,3,2) => 2 irb(main):030:0> median(2,1,3) => 2 irb(main):031:0> median(3,1,2) => 2
def median(x,y,z) if x>y if y>z y elsif x>z z else x end elsif x>z x elsif y>z z else y end endとなりもう少しすっきり書ける.
def median(x,y,z) if (y<=x && x<=z) || (z<=x && x<=y) x else if (x<=y && y<=z) || (z<=y && y<=x) y else z end end endこちらはすっきりと書けるが,同じ条件判断を繰り返す(たとえば,x=3,y=2,z=1の時には,x<=yやy<=xを何度もチェックする)ので本当に速度が必要なところでは問題がでることはある. なお,この問題ではx,y,zが異なる値だとしているので「<=」としているのは, 「<」でも動くが,「<=」とすると同じ値が含まれているときも正しい値(x=y< zの ときはx(y)が中央値)を返す.なお, この条件を奇麗に書くために,
def median(x,y,z) if (y-x)*(z-x)<=0 x else if (x-y)*(z-y)<=0 y else z end end endと書いている人もいて,これも正解ではある(「<=」としているのは, 「<」でも動くが,「<=」とすると同じ値が含まれているときも正しい値を返す). ただ,Ruby言語でx,y,zが整数値の時は問題ないが,整数値の範囲に制限がある言 語では正しく動かない場合がある.
def max(x,y) if x>y x else y end end def min(x,y) if x>y y else x end end def median(x,y,z) x+y+z-max(x,max(y,z))-min(x,min(y,z)) endというトリッキーな解法もある(これも整数値の範囲に制限がある言語では正しく 動かない場合がある).Ruby言語では,配列中の最大値を「式.max()」, 最小値を 「式.min()」で得られるので,それを使うと
def median(x,y,z) x+y+z-[x,y,z].max()-[x,y,z].min() endのように短く書ける.
def median(x,y,z) [[x,y].min(),[y,z].min(),[z,x].min()].max()というのも分かりやすい解ではある.
def median(x, y, z) ( ([x, y, z]).sort() )[1] endとする解もあった.「牛刀を以て鶏を割く 」ような解だが,発想は面白い.受け狙いで,
def median(x, y, z) if x <= y and y <= z return y else if rand(2) == 0 return median(y, x, z) else return median(x, z, y) end end endとしていたものあった(「rand(2)」は「6.2 乱数とMonte Carlo法」でやるので,ここでは理解しなくても良い).
def det(a,b,c) b**2-4*a*c end def solutions(a,b,c) d=det(a,b,c) if a==0 || d==0 1 else if d>0 2 else 0 end end endのようなもので,実行例は
irb(main):045:0* solutions(0,1,2) => 1 irb(main):047:0* solutions(1,3,2) => 2 irb(main):049:0* solutions(1,2,1) => 1 irb(main):050:0> solutions(1,2,3) => 0となる.
def solutions(a,b,c) if a==0 || det(a,b,c)==0 1 else if det(a,b,c)>0 2 else 0 end end endでも良いが,答えが2の時に同じ計算det(a,b,c)を2回計算するのが気になる人 がいるかもしれない.賢いプログラミング言語処理系では,後者のように書いても前者のように変換してくれることもある.
中央値を求めるのに, def median(x,y,z) min(max(x,y),max(y,z)) endで良いと一瞬思えてしまうかもしれないが,3!=6通りのケースを考えてみると,
median(1,3,2) -> 3と誤った答えを返すことがあることに気がつくだろう.
ruby vote.rb 選択肢番号のように使う.