LoginSignup
6
6

More than 5 years have passed since last update.

その first は本当に必要なのか

Last updated at Posted at 2016-07-21

要素数が必ず1になる配列から値を取り出すという状況には、意外と遭遇すると思います・・・・いや、やっぱりしないかもしれません。例えばrailsだと・・・

# emailカラムはユニーク
User.where(email: 'sample@gmal.com').first

みたいなのです。find_by使えと突っ込まれそうですが、実際に業務の中でこのようなコードには頻繁に遭遇します(自分で書くことはありませんが・・・)。

私が現在扱っている自社メディアのコード内に限った話ですが、このような処理を行っている箇所では、必ずと言っていいほどfirstを使って値を取り出していました

そのfirstに意味はあるのか

[1].first

上記の処理を日本語で説明するなら、"要素数が1の配列から、先頭の要素を取り出す"と言えると思います。ここでは先頭の要素を選択していますが、そもそも選択候補が1つしかないわけです。結果、メソッドの意味とコード中での目的が食い違うこととなり、コードの可読性を落としてしまいます。こういった処理は避けたほうがいい気がします。しかし、実際このような記述は、苦肉の策として理解できなくもありません。

そもそも何が言いたいのか

何が伝えたいのか分からなくなってきましたが、結局言いたいのは・・・
firstとかが出てくるコードには、何らかの技術的負債があるかもしれないということです。あくまでも私見であり、これらが効果的に使える場面も多々あるとは思います。

以下、おまけです。

仕方がない場合はどうするか

では、"要素数が1の配列から、値を取り出す"という行為がどうしても必要な場合はどうしましょう。例えばfirst以外にも代替案として以下のようなものがありますが・・・

[1].first
[1].last
[1].sample
[1].pop
[1][0]

いずれも目的とは意味が食い違います。

せめて処理が速いものを

どーせ無理なら少しでも速いものを選択したいです。というわけで、以下の処理を行い、処理速度を計測してみました。

# helloという文字列が入った要素数1の配列を2000000個持つ配列を宣言
array = Array.new(2000000).map { Array.new(1, 'hello')}

# 実行時間計測用
t = Time.now

array.each do |val|
  val # ここを変化させて、それぞれ処理時間を計測する
end

p Time.now - t

上記のコードで、each内のvalを随時変更して、処理にかかった時間を計測してみました。10回の平均値をとっています。

コード 実行時間
val(要素を取り出さない) 0.078 s
val.first 0.119 s
val.last 0.118 s
val.sample 0.125 s
val[0] 0.099 s

当然ではありますが、val[0]が明らかに速いです。

また、タイプ数で比較すると、firstが5タイプlastが4タイプ[0]が3タイプです。しかし、[0]はホームポジションから遠いため、少し打ちずらいですね。というわけで、タイピングの打ち易さから考えると、lastが最善に思えます(firstとlastに速度差はないですし)。

結局どうすればいいのか

処理が速いのは文句なしにval[0]の書き方です。打ち易いのはlastですかね。ですが、これがいいのかというと正直微妙です。そもそも、 "要素数が1と確定している配列から値を取り出す" という処理なんかするなって話ですが・・・

何か助言がありましたら、ぜひお願いします。

6
6
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6