数、サイズ、長さ…Rubyの選択肢が多すぎる?


140

私はこれについて決定的な答えを見つけることができないようで、私がこれを「n番目のレベル」まで確実に理解したいと思います:-)

    a = {"a" => "こんにちは"、 "b" => "世界"}
    a.count#2
    a.size#2
    a.length#2

    a = [10、20]
    a.count#2
    a.size#2
    a.length#2

それでどちらを使うのですか?aに複数の要素があるかどうかを知りたい場合、それは問題ではないようですが、実際の違いを確実に理解したいと思います。これは配列にも当てはまります。同じ結果が得られます。

また、カウント/サイズ/長さはActiveRecordとは異なる意味を持つことに気づきました。今は主に純粋なRuby(1.92)に関心がありますが、ARがもたらす違いを誰かが知りたいのであれば、それも評価されます。

ありがとう!


5
発生した現象は、TMTOWTDIと呼ばれることもあります。それを行う方法は1つではありません。このスローガンはPerlコミュニティからのものであり、PerlはRubyへの影響の1つです。
Andrew Grimm、

これらは通常、お互いのエイリアスです-同じことをします。また、覚えておくべきメソッドが1つArray#nitemsあります。これは、配列内の非NILアイテムの数を返します。しかし、Ruby 1.9では利用できなくなりました
Tilo

回答:


194

配列とハッシュsizeはのエイリアスですlength。それらは同義語であり、まったく同じことを行います。

count より用途が広い-要素または述語を取り、一致する項目のみをカウントできます。

> [1,2,3].count{|x| x > 2 }
=> 1

カウントするパラメーターを指定しない場合、基本的に長さを呼び出すのと同じ効果があります。ただし、パフォーマンスに違いが生じる可能性があります。

Arrayソースコードから、ほぼ同じことを行うことがわかります。以下は、を実装するためのCコードですarray.length

static VALUE
rb_ary_length(VALUE ary)
{
    long len = RARRAY_LEN(ary);
    return LONG2NUM(len);
}

そしてここに実装の関連部分がありますarray.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));

        // etc..
    }
}

のコードarray.countはいくつかの追加チェックを行いますが、最終的にはまったく同じコードを呼び出しますLONG2NUM(RARRAY_LEN(ary))

一方、ハッシュ(ソースコード)は独自の最適化されたバージョンのを実装していないようなcountので、Enumerableソースコード)の実装が使用され、すべての要素を反復して1つずつカウントします。

全体でいくつの要素があるかを知りたいのではなく、一般にlength(またはそのエイリアスsize)を使用countすることをお勧めします。


一方、ActiveRecordに関しては、重要な違いがあります。この投稿をチェックしてください:


10

データベース接続を利用するアプリケーションには決定的な違いがあります。

多くのORM(ActiveRecord、DataMapperなど)を使用している場合、一般的な理解として、.sizeはデータベースからすべてのアイテムを要求するクエリを生成し( 'select * from mytable')、アイテムの数を提供します。結果として、.countは単一のクエリ( 'select count(*)from mytable')を生成しますが、これはかなり高速です。

これらのORMは非常に普及しているので、私は最小の驚きの原則に従っています。一般に、すでにメモリに何かがある場合は.sizeを使用し、コードがデータベース(またはAPIを介した外部サービス)へのリクエストを生成する場合は.countを使用します。


1
これで考慮すべきことはcounter_cacheです。テーブルがfooあり、そのhas_many barがある場合、が作成または破棄されるたびに更新されるfoo名前付きの列があります。を使用すると、その列がチェックされます(実際にはをクエリしません)。キャッシュの目的を無効にする実際のクエリを実行します。bars_countbarfoo.bars.sizebarsfoo.bars.count
Dudo

7

ほとんどの場合(例えばに配列または文字列sizeである別名のためにlength

count通常はEnumerableから取得され、オプションの述語ブロックを使用できます。したがってenumerable.count {cond}、[大まかに] (enumerable.select {cond}).length-一致する述語の数が必要なだけなので、もちろん中間構造をバイパスできます。

注:ブロックが指定されていない場合、または可能であれば短絡する場合に、列挙の評価をcount 強制するかどうかはわかりませんlength

編集(およびMarkの回答のおかげで!): count ブロックがない場合(少なくとも配列の場合)、評価強制されません。述語なしで評価を強制することがとにかく本当に理にかなっているならば、私は正式な振る舞いがなければ他の実装に対して「オープン」であると思います。


5

http://blog.hasmanythrough.com/2008/2/27/count-length-sizeで良いアンスウェアを見つけました

ActiveRecordには、アソシエーションに含まれるレコードの数を調べる方法がいくつかあり、それらの動作には微妙な違いがあります。

post.comments.count-SQL COUNTクエリで要素の数を決定します。関連付けられた要素のサブセットのみをカウントする条件を指定することもできます(例::conditions => {:author_name => "josh"})。アソシエーションにカウンタキャッシュを設定すると、#countは新しいクエリを実行する代わりに、キャッシュされた値を返します。

post.comments.length-これは常に関連付けのコンテンツをメモリにロードし、ロードされた要素の数を返します。関連付けが以前にロードされていて、新しいコメントが別の方法で作成された場合(たとえば、post.comments.create(...)ではなくComment.create(...))、これは更新を強制しません。

post.comments.size-これは、前の2つのオプションの組み合わせとして機能します。コレクションが既にロードされている場合は、#lengthを呼び出すのと同じように、コレクションの長さが返されます。まだ読み込まれていない場合は、#countを呼び出すようなものです。

また、私には個人的な経験があります:

<%= h(params.size.to_s) %> # works_like_that !
<%= h(params.count.to_s) %> # does_not_work_like_that !

2

私たちは、のような配列でどのように多くの要素を見つけるには、いくつかの方法があり.length.countそして.size。ただし、array.sizeではなくを使用することをお勧めしますarray.count.sizeパフォーマンスが良いからです。


1

Mark Byersの回答にさらに追加します。Rubyでは、このメソッドarray.sizeArray#lengthメソッドのエイリアスです。これら2つの方法のいずれを使用しても、技術的な違いはありません。おそらく、パフォーマンスの違いもわかりません。ただし、array.countも同じ処理を行いますが、いくつかの追加機能を備えています。Array#count

ある条件に基づいて要素の総数を取得するために使用できます。Countは次の3つの方法で呼び出すことができます。

Array#count配列の要素数を返します

Array#count n #配列の値nを持つ要素の数を返します

Array#count {| i | i.even?} 各要素配列で呼び出された条件に基づいてカウントを返します

array = [1,2,3,4,5,6,7,4,3,2,4,5,6,7,1,2,4]

array.size     # => 17
array.length   # => 17
array.count    # => 17

ここで、3つのメソッドはすべて同じ働きをします。しかし、ここcountが興味深いところです。

配列に値2が含まれる配列要素の数を調べたいとしましょう

array.count 2    # => 3

配列には、値が2の合計3つの要素があります。

ここで、4より大きい配列要素をすべて検索したい

array.count{|i| i > 4}   # =>6

配列には、4より大きい>合計6つの要素があります。

私はそれがcount方法に関するいくつかの情報を与えることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.