Array#both_endの使いどころを考える

はじめに

Array#minimaxというメソッドがRuby 2.4から導入されていて、そのメソッドの実装を読んでいた時に思いついたArray#both_endメソッドの実用例についてつらつらと書いてみた記事。

なので、実際にRubyにそういうメソッドがあるわけではない。

実装

/*
 *  call-seq:
 *     ary.both_end     ->  new_ary
 *     ary.both_end(n)  ->  new_ary
 *
 *  Returns the last element(s) of +self+. If the array is empty,
 *  the first form returns +nil+.
 *
 *  See also Array#first for the opposite effect.
 *
 *     a = [ "w", "x", "y", "z" ]
 *     a.both_end     #=> ["w", "z"]
 *     a.both_end(2)  #=> [["w", "x"], ["y", "z"]
 *     [].both_end    #=> [nil, nil]
 */

static VALUE
rb_ary_both_end(int argc, VALUE *argv, VALUE ary)
{
    VALUE first, last;

    rb_check_arity(argc, 0, 1);

    if (RARRAY_LEN(ary) == 0)
        return rb_assoc_new(Qnil, Qnil);

    first = rb_ary_first(argc, argv, ary);
    last = rb_ary_last(argc, argv, ary);

    return rb_assoc_new(first, last);
}

実装はこんな感じで、内部のコードではArray#firstArray#lastを呼び出してる。最後にrb_assoc_newで新しくArrayを作って返している。

空のArrayの場合は[nil, nil]が返えるようになっている。

現状の使いどころ

Arrayの両端の値を指定の数だけとってきたい時に使う感じ

ary = [1, 2, 3, 4, 5]

result = ary.both_end(2)

puts result.first == [1, 2]
# => true

puts result.last == [4, 5]
# => true

あとはこんな感じでArrayの両端を使った繰り返し書くときとか?

ary = [1, 2, 3, 4, 5]

result = ary.both_end(2)

result[0].map{|a1|
  result[1].map{|a2|
    puts a1 == a2
  }
}

Railsとかで使う場合は、最新と最古のデータとってきたい時に一行で書けるかもしれない?

@result = Topic.both_end(3)
# => 最新と最古のデータを三件づつとってくるイメージ

現状の問題点?

内部の実装でArray#firstArray#lastを使っているのでこういうコードはエラーにならない。

ary = [1, 2, 3, 4, 5]

result = ary.both_end(10)
# => [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]

エラーになった方が自然なのかどうなのかは判断できなかったので、そのままにしてるけどエラーのほうが良いのだろうか? まあ、要素が同じArrayを複数持つことができるのでエラーにならない方が恩恵ありそうかも。

ary = [1, 2, 3, 4, 5]

result = ary.both_end(10)
# => [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]

a1 = result.first
a2 = result.last
# => [1, 2, 3, 4, 5]がそれぞれに入る

まとめ

とりあえず、最新と最古のデータとってきたりするときには使えそうかなぁという感じ。 今後も仕様とか検討してみるけど、提案するかはまだ保留。

もし、記事を読んだ方で興味のある方はコメントとかいただけると助かります