Python のリスト(Ruby の配列)のスライスを Ruby で実装

曇。
夜更ししてプロジェクト・オイラーで遊んでいる。Ruby のメソッドで時々欲しくなるのが、配列の最後を切り落とすメソッド。pop は切り落とした内容が返されてしまうので、切り落とされた配列の方が返って欲しいのである。

class Array
  def chop
    a = self.dup
    a.pop
    a
  end
end

p [0, 1, 2, 3].chop    #=> [0, 1, 2]

あるいはこういう実装でもよい。 上よりこちらの方が短く書けていてかつ高機能のように見えるが、たぶん上の方が速い。と予想して計測してみたら、こちらの方が速かった(約1.3倍)。こっちにしよう。

class Array
  def chop(n=1)
    self[0, self.size - n]
  end
end

p ["a", "b", "c"].chop    #=>["a", "b"]
p [0, 1, 2, 3, 4, 5].chop(2)    #=>[0, 1, 2, 3]

破壊的なメソッドを作ってもよいだろう。

class Array
  def chop!(n=1)
    self.replace(self[0, self.size - n])
  end
end

a = [0, 1, 2, 3, 4, 5]
a.chop!(2)
p a    #=>[0, 1, 2, 3]

Ruby はモンキーパッチが超簡単である。モンキーパッチはあまり勧められないという人もいるけれど、こういうのなら特に問題はないだろう。言語を楽に拡張するようで、僕は好きである。ただ、既存のメソッドにモンキーパッチを当てるというのはむずかしい。
※参考:分別のあるRubyモンキーパッチャーになるために
まてよ、

class Array
  def chop(n=1)
    self[0..(- 1 - n)]
  end
end

p [0, 1, 2, 3, 4, 5].chop(2)    #=>[0, 1, 2, 3]

でいいのか。これなら別にメソッドなしでもいけるな。範囲演算子でマイナスを使うと。にゃんと、見落としていたね。おもしろいことに、これだと引数をマイナスにすれば、先頭から引数分(の絶対値)だけ残して末尾を切り落とすことになる。ってそんなの使う人がいないけれど。だって [0, 1, 2, 3, 4, 5][0, 2] で充分だからな。読みやすいかどうかだけだね。

p [0, 1, 2, 3, 4, 5].chop(-2)    #=>[0, 1]


Python のリスト(Ruby の配列)のスライスを Ruby で実装するのに没頭(参照)。苦労した。(AM3:25)
ティーヴ・エリクソンを読む。あんまりにも暗い話。