Hitung, ukuran, panjang ... terlalu banyak pilihan di Ruby?

140

Sepertinya saya tidak dapat menemukan jawaban yang pasti tentang ini dan saya ingin memastikan saya memahami ini ke "tingkat ke-n" :-)

    a = {"a" => "Hello", "b" => "World"}
    a.count # 2
    ukuran # 2
    panjang # 2

    a = [10, 20]
    a.count # 2
    ukuran # 2
    panjang # 2

Jadi mana yang harus digunakan? Jika saya ingin tahu apakah a memiliki lebih dari satu elemen maka sepertinya tidak masalah tetapi saya ingin memastikan saya memahami perbedaan yang sebenarnya. Ini berlaku untuk array juga. Saya mendapatkan hasil yang sama.

Juga, saya menyadari bahwa jumlah / ukuran / panjang memiliki arti yang berbeda dengan ActiveRecord. Saya sebagian besar tertarik pada Ruby murni (1,92) sekarang tetapi jika ada yang ingin berpadu pada perbedaan AR membuat itu akan dihargai juga.

Terima kasih!

cbmeeks
sumber
5
Fenomena yang Anda temui kadang-kadang disebut TMTOWTDI : Ada Lebih dari Satu Cara Untuk Melakukannya. Slogan ini berasal dari komunitas Perl, dan Perl adalah salah satu pengaruhnya terhadap Ruby.
Andrew Grimm
ini biasanya alias satu sama lain - mereka melakukan hal yang sama. Ada satu metode yang juga harus Anda ingat Array#nitems:, yang mengembalikan jumlah item non-NIL dalam array. Tapi itu tidak tersedia di Ruby 1.9 lagi
Tilo

Jawaban:

194

Untuk array dan hash sizeadalah alias untuk length. Mereka sinonim dan melakukan hal yang persis sama.

count lebih fleksibel - dapat mengambil elemen atau predikat dan hanya menghitung item yang cocok.

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

Dalam kasus di mana Anda tidak memberikan parameter untuk menghitungnya pada dasarnya memiliki efek yang sama dengan panjang panggilan. Mungkin ada perbedaan kinerja.

Kita dapat melihat dari kode sumber untuk Array bahwa mereka melakukan hal yang persis sama. Berikut adalah kode C untuk implementasi array.length:

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

Dan inilah bagian yang relevan dari implementasi 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..
    }
}

Kode untuk array.countmelakukan beberapa pemeriksaan tambahan namun pada akhirnya panggilan kode yang sama persis: LONG2NUM(RARRAY_LEN(ary)).

Hash ( kode sumber ) di sisi lain tampaknya tidak mengimplementasikan versi dioptimalkan mereka sendiri countsehingga implementasi dari Enumerable( kode sumber ) digunakan, yang iterates atas semua elemen dan menghitungnya satu per satu.

Secara umum saya akan menyarankan menggunakan length(atau alias size) daripada countjika Anda ingin tahu berapa banyak elemen yang ada.


Mengenai ActiveRecord, di sisi lain, ada yang perbedaan penting. lihat posting ini:

Mark Byers
sumber
10

Ada perbedaan penting untuk aplikasi yang memanfaatkan koneksi basis data.

Ketika Anda menggunakan banyak ORM (ActiveRecord, DataMapper, dll.) Pemahaman umum adalah bahwa .size akan menghasilkan permintaan yang meminta semua item dari database ('pilih * dari mytable') dan kemudian memberi Anda jumlah item dihasilkan, sedangkan .count akan menghasilkan satu permintaan ('pilih hitungan (*) dari mytable') yang jauh lebih cepat.

Karena ORM ini sangat lazim saya mengikuti prinsip paling tidak heran. Secara umum jika saya sudah memiliki sesuatu di memori, maka saya menggunakan .size, dan jika kode saya akan menghasilkan permintaan ke database (atau layanan eksternal melalui API) saya menggunakan .count.

Stefan
sumber
1
Sesuatu yang perlu dipertimbangkan dengan ini counter_cache. Jika memiliki tabel,, foodan has_many bar, Anda akan memiliki kolom dengan foonama bars_countyang diperbarui kapan saja a bardibuat / dihancurkan. Menggunakan foo.bars.sizeadalah apa yang memeriksa kolom itu (tanpa benar-benar bertanya bars). foo.bars.countmelakukan permintaan aktual, yang akan mengalahkan tujuan cache.
Dudo
7

Dalam kebanyakan kasus (misalnya Array atau String ) sizeadalah alias untuk length.

countbiasanya berasal dari Enumerable dan dapat mengambil blok predikat opsional. Jadi enumerable.count {cond}[kira-kira] (enumerable.select {cond}).length- tentu saja dapat mem-bypass struktur perantara karena hanya perlu hitungan predikat yang sesuai.

Catatan: Saya tidak yakin apakah count memaksa evaluasi enumerasi jika blok tidak ditentukan atau jika terjadi hubungan pendek ke lengthjika mungkin.

Sunting (dan terima kasih atas jawaban Markus!): count Tanpa blok (setidaknya untuk Array) tidak memaksa evaluasi. Saya kira tanpa perilaku formal itu "terbuka" untuk implementasi lain, jika memaksakan evaluasi tanpa predikat bahkan benar-benar masuk akal.


sumber
5

Saya menemukan answare yang bagus di http://blog.hasmanythrough.com/2008/2/27/count-length-size

Dalam ActiveRecord, ada beberapa cara untuk mengetahui berapa banyak catatan dalam suatu asosiasi, dan ada beberapa perbedaan halus dalam cara kerjanya.

post.comments.count - Menentukan jumlah elemen dengan kueri COUNT SQL. Anda juga dapat menentukan kondisi untuk menghitung hanya subset dari elemen terkait (mis: conditions => {: author_name => "josh"}). Jika Anda menyiapkan penghitung cache pada asosiasi, #count akan mengembalikan nilai yang di-cache itu alih-alih menjalankan kueri baru.

post.comments.length - Ini selalu memuat konten asosiasi ke dalam memori, lalu mengembalikan jumlah elemen yang dimuat. Perhatikan bahwa ini tidak akan memaksa pembaruan jika asosiasi sebelumnya dimuat dan kemudian komentar baru dibuat melalui cara lain (mis. Comment.create (...) alih-alih post.comments.create (...)).

post.comments.size - Ini berfungsi sebagai kombinasi dari dua opsi sebelumnya. Jika koleksi telah dimuat, itu akan mengembalikan panjangnya seperti memanggil #length. Jika belum dimuat, itu seperti memanggil #count.

Saya juga punya pengalaman pribadi:

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

Kami memiliki beberapa cara untuk mengetahui berapa banyak elemen dalam array seperti .length, .countdan .size. Namun, lebih baik menggunakan array.sizedaripada array.count. Karena .sizekinerjanya lebih baik.

Venkat M
sumber
1

Menambahkan lebih banyak ke jawaban Mark Byers. Di Ruby metode array.sizeini adalah alias untuk metode panjang # Array . Tidak ada perbedaan teknis dalam menggunakan salah satu dari kedua metode ini. Mungkin Anda tidak akan melihat perbedaan dalam kinerja juga. Namun, array.countjuga melakukan pekerjaan yang sama tetapi dengan beberapa fungsionalitas tambahan # jumlah hitungan

Dapat digunakan untuk mendapatkan total no elemen berdasarkan kondisi tertentu. Hitung dapat dipanggil dengan tiga cara:

Array # count # Mengembalikan jumlah elemen dalam Array

Array # count n # Mengembalikan jumlah elemen yang memiliki nilai n dalam Array

Array # count {| i | i.even?} Pengembalian dihitung berdasarkan kondisi yang dilakukan pada setiap array elemen

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

Di sini ketiga metode melakukan pekerjaan yang sama. Namun di sinilah countsemakin menarik.

Katakanlah, saya ingin menemukan berapa banyak elemen array yang berisi array dengan nilai 2

array.count 2    # => 3

Array memiliki total tiga elemen dengan nilai 2.

Sekarang, saya ingin menemukan semua elemen array yang lebih besar dari 4

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

Array memiliki total 6 elemen yang> dari 4.

Saya harap ini memberikan beberapa info tentang countmetode.

Prabhakar Undurthi
sumber