Rubyにおいて要素有無判定にはcountよりempty?使おう、というゆるふわ話
弊社では担当プロダクトごとにエンジニアが複数人付く体制でWEBサービスの開発運用やってます。 その過程でコードレビューを実施してるわけなんですが、
とある日、他の人のコード見ていて要素があるかないか、をこう判定しているコードを見つけました。
## items: Array return false if items.count == 0
countだと要素の数え上げしちゃうんでempty?使った方が効率いいっすよ、というレビューコメントを書いたわけですよ。 その時ふと、「本当にempty?のほうが良いのか?」という疑問が(;・`д・)
気になったので、少し深掘りしました。
countを使う場合
rubyはソースコードが公開されてるので、それを見ます。 https://github.com/ruby/ruby/blob/trunk/array.c
rb_ary_countっていうものが該当します。
static VALUE rb_ary_count(int argc, VALUE *argv, VALUE ary) { long n = 0; if (argc == 0) { VALUE *p, *pend; if (!rb_block_given_p()) return LONG2NUM(RARRAY_LEN(ary)); for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (RTEST(rb_yield(*p))) n++; } } else { VALUE obj, *p, *pend; rb_scan_args(argc, argv, "1", &obj); if (rb_block_given_p()) { rb_warn("given block not used"); } for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (rb_equal(*p, obj)) n++; } } return LONG2NUM(n); }
予想どおり、forを回してカウントとってますね。
empty?を使う場合。
一方empty?。これも同じソースコード中に定義が存在します。中身こんなんです。
static VALUE rb_ary_empty_p(VALUE ary) { if (RARRAY_LEN(ary) == 0) return Qtrue; return Qfalse; }
RARRAY_LENしか読んでませんね。中身見るとこうなってます。
#define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
arrayが持っているlenというメンバに対して値を取得して判定してますね。
empty?では、要素数え上げしてないので、countより計算量は少ないわけですな。
まあ、この程度の数え上げする・しないの話は、全体の影響度からするとごくわずかな違いでしか無いので、普通にWebやってるだけなら気にする必要はないんですが、実際に蓋開けた結果を知っておくのも大事だと思いました。