どう書くで見る ruby の便利機能

  • 22
    いいね
  • 0
    コメント

この記事は Ruby Advent Calendar 2016の20日目の記事のつもりで書いている。

Advent Calendar というものに参加するのは初めてなので緊張している。

実務ではあまり ruby を使っていないので、私は自分が主催しているどう書く( https://yhpg.doorkeeper.jp/ )での ruby の使われ方を書こうと思う。

思いついた順なので、ごちゃごちゃするけど気にしない方向で。

Array#transpose

行列ではないものをtransposeできる言語が他にあるかどうか知らないんだけど、transposeは便利。

x方向で処理するプログラムだけを用意しておいて、y方向の処理は、データを transpose したものを渡すことで済ますとか。

あるいは、平面的なものを回転するときに役に立つ。

2次元配列をreverseしてからtransposeすると時計回りに、transposeしてからreverseすると反時計回りに回せる。

Object#tap〜break

メソッドチェインをしていくなかで、パスしていくオブジェクトを $x$ から $f(x)$ に変更したい場合に使う。

foo.略{略}.略{略}.tap{ |x| break f(x) }.略{略}

のような感じ。

標準で存在して然るべきメソッドだと思う。

Integer#divmod

除算の結果の商と剰余がいっぺんに手に入る。

123.divmod(100) #=> [1, 23]

一次元的に表現された平面から座標を取るときに活躍する。
配列でもらえるので、そのままメソッドチェインに流し込んだりするのも便利。

Array#minmax

min と max がいっぺんに手に入る。

"helloworld".chars.minmax # => ["d", "w"]

こんな感じ。
これもそのままメソッドチェインに流すことが出来る。便利。

String#ord Integer#chr

"a"〜"z" を 0〜25 などに変換する必要がある場面は多いので、n=c.ord-?a.ord のような計算はよく出てくる。
逆変換は、c=(n+?a.ord).chr

Integer#[ ]

Integerには123[4] のように呼べるメソッドがあって、トラブルの原因になりやすいような気もするけど、ビット演算が簡単にできるのはとても便利。
先の例は、( (123 & (1<<4))==0 )? 0 : 1 と同じなので、

123[4] # => 1

ちなみに、Integer#[ ]= はない。

Array#& と Array#|

[1,1,2,3,4,4] & [3,4,4,5] # => [3, 4]
[1,1,2,3,4,4] | [3,4,4,5] # => [1, 2, 3, 4, 5]

のように、Array#uniq の処理を含んでいることに注意。というか、そこもわかっていると便利。

Math.log2 と Math.cbrt

Math.log2 は、 $\frac{\ln(x)}{\ln(2)}$ の計算をする。何に使うのかというと、場合の数。
なので、Math.log2(x).ceil のような感じで、ceilfloor とセットで使うと思う。

Math.log(x)/Math.log(2) のような計算と違って、誤差が出にくい。

Math.log(2**29)/Math.log(2) #=> 29.000000000000004
Math.log2(2**29) #=> 29.0

そういえば、三乗根の Math.cbrt が便利だったこともある:

64**(1.0/3) # => 3.9999999999999996
Math.cbrt(64) #=> 4.0

こちらも誤差が出にくい。

オープンクラスの悪用

たとえば、平面上の座標を配列で表現しようと思うとする。
そんなとき、

class Array
  def x; self[0]; end
  def y; self[1]; end
end

のような悪用をすると結構便利。仕事だと許されないと思うけど、どう書くならアリだと思う。

Array#combination と仲間たち

Array には、combination, permutation, repeated_combination, repeated_permutation という4つの便利メソッドがある。

それぞれ名前のとおりなんだけど、実行結果は以下の通り:

[1,2,3].combination(2).to_a
#=> [[1, 2], [1, 3], [2, 3]]
[1,2,3].permutation(2).to_a
#=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
[1,2,3].repeated_combination(2).to_a
#=> [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]]
[1,2,3].repeated_permutation(2).to_a
#=> [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]

実際に書こうとすると再帰だったりして面倒になるので、これがあるのは本当に助かる。というか、出題者としては困るぐらい便利。

【宣伝】

現在、私が主催するオフラインリアルタイムどう書くでは

の参加者を募集しています。

この投稿は Ruby Advent Calendar 201620日目の記事です。