Đếm, kích thước, chiều dài, quá nhiều sự lựa chọn trong Ruby?


140

Tôi dường như không thể tìm thấy một câu trả lời dứt khoát về điều này và tôi muốn chắc chắn rằng tôi hiểu điều này đến "cấp độ thứ nhất" :-)

    a = {"a" => "Xin chào", "b" => "Thế giới"}
    số 2
    kích thước # 2
    thứ hai

    a = [10, 20]
    số 2
    kích thước # 2
    thứ hai

Vậy nên dùng loại nào? Nếu tôi muốn biết nếu một có nhiều hơn một yếu tố thì điều đó dường như không quan trọng nhưng tôi muốn chắc chắn rằng tôi hiểu sự khác biệt thực sự. Điều này áp dụng cho mảng quá. Tôi nhận được kết quả tương tự.

Ngoài ra, tôi nhận ra rằng số lượng / kích thước / chiều dài có ý nghĩa khác nhau với ActiveRecord. Tôi hầu như quan tâm đến Ruby thuần túy (1.92) ngay bây giờ nhưng nếu bất cứ ai muốn nhấn mạnh vào sự khác biệt thì AR cũng sẽ được đánh giá cao.

Cảm ơn!


5
Hiện tượng bạn gặp phải đôi khi được gọi là TMTOWTDI : Có nhiều cách để làm điều đó. Khẩu hiệu này đến từ cộng đồng Perl và Perl là một trong những người có ảnh hưởng đến Ruby.
Andrew Grimm

chúng thường là bí danh cho nhau - chúng làm như vậy. Có một phương pháp bạn cũng nên ghi nhớ : Array#nitems, trả về số lượng các mục không NIL trong một mảng. Nhưng điều đó không có sẵn trong Ruby 1.9 nữa
Tilo

Câu trả lời:


194

Đối với mảng và băm sizelà một bí danh cho length. Chúng là từ đồng nghĩa và làm chính xác điều tương tự.

count linh hoạt hơn - nó có thể lấy một yếu tố hoặc vị ngữ và chỉ đếm những mục phù hợp.

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

Trong trường hợp bạn không cung cấp một tham số để đếm thì về cơ bản nó có tác dụng tương tự như thời lượng gọi. Có thể có một sự khác biệt hiệu suất mặc dù.

Chúng ta có thể thấy từ mã nguồn cho Array rằng họ thực hiện gần như chính xác điều tương tự. Đây là mã C để thực hiện array.length:

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

Và đây là phần có liên quan từ việc thực hiện 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..
    }
}

Mã cho array.countmột vài kiểm tra bổ sung nhưng cuối cùng gọi chính xác mã : LONG2NUM(RARRAY_LEN(ary)).

Mặt khác, băm ( mã nguồn ) dường như không thực hiện phiên bản tối ưu hóa của riêng chúng countđể việc triển khai từ Enumerable( mã nguồn ) được sử dụng, lặp đi lặp lại trên tất cả các yếu tố và đếm từng cái một.

Nói chung, tôi khuyên bạn nên sử dụng length(hoặc bí danh của nó size) thay vì countnếu bạn muốn biết có bao nhiêu phần tử hoàn toàn.


Về ActiveRecord, mặt khác, có những khác biệt quan trọng. kiểm tra bài này:


10

Có một sự khác biệt quan trọng đối với các ứng dụng sử dụng kết nối cơ sở dữ liệu.

Khi bạn đang sử dụng nhiều ORM (ActiveRecord, DataMapper, v.v.), sự hiểu biết chung là .size sẽ tạo một truy vấn yêu cầu tất cả các mục từ cơ sở dữ liệu ('select * từ mytable') và sau đó cung cấp cho bạn số lượng mục kết quả là, trong khi .count sẽ tạo một truy vấn duy nhất ('select Count (*) từ mytable') nhanh hơn đáng kể.

Bởi vì các ORM này rất phổ biến, tôi tuân theo nguyên tắc ít ngạc nhiên nhất. Nói chung, nếu tôi đã có một cái gì đó trong bộ nhớ, thì tôi sử dụng .size và nếu mã của tôi sẽ tạo một yêu cầu tới cơ sở dữ liệu (hoặc dịch vụ bên ngoài thông qua API) tôi sử dụng .count.


1
Một cái gì đó để xem xét với điều này là counter_cache. Nếu có một bảng foovà nó có_many bar, bạn sẽ có một cột foocó tên bars_countđược cập nhật bất cứ khi nào a barđược tạo / hủy. Sử dụng foo.bars.sizelà những gì kiểm tra cột đó (mà không thực sự truy vấn bất kỳ bars). foo.bars.countthực hiện truy vấn thực tế, sẽ đánh bại mục đích của bộ đệm.
Dudo

7

Trong hầu hết các trường hợp (ví dụ Array hoặc String ) sizebí danh cho length.

countthường đến từ Vô số và có thể lấy một khối vị ngữ tùy chọn. Như vậy enumerable.count {cond}là [đại khái](enumerable.select {cond}).length - tất nhiên nó có thể bỏ qua cấu trúc trung gian vì nó chỉ cần số lượng vị từ phù hợp.

Lưu ý: Tôi không chắc chắn nếu count buộc phải đánh giá phép liệt kê nếu khối không được chỉ định hoặc nếu nó bị đoản mạch lengthnếu có thể.

Chỉnh sửa (và nhờ câu trả lời của Mark!): Không count có khối (ít nhất là cho Mảng) không buộc phải đánh giá. Tôi cho rằng không có hành vi chính thức thì nó "mở" cho các triển khai khác, nếu buộc đánh giá mà không có một vị từ thậm chí thực sự có ý nghĩa dù sao đi nữa.


5

Tôi đã tìm thấy một phần mềm answare tốt tại http: //blog.hasmany phiên.com / 2008/27/27 / Count-length-size

Trong ActiveRecord, có một số cách để tìm hiểu có bao nhiêu bản ghi trong một liên kết và có một số khác biệt tinh tế trong cách chúng hoạt động.

post.comments.count - Xác định số lượng phần tử với truy vấn SQL COUNT. Bạn cũng có thể chỉ định các điều kiện để chỉ đếm một tập hợp con của các phần tử được liên kết (ví dụ: điều kiện => {: Author_name => "josh"}). Nếu bạn thiết lập bộ đệm bộ đếm trên liên kết, #count sẽ trả về giá trị được lưu trong bộ nhớ cache đó thay vì thực hiện một truy vấn mới.

post.comments.length - Điều này luôn tải nội dung của liên kết vào bộ nhớ, sau đó trả về số lượng phần tử được tải. Lưu ý rằng điều này sẽ không bắt buộc cập nhật nếu liên kết đã được tải trước đó và sau đó các nhận xét mới được tạo thông qua một cách khác (ví dụ: Comment.create (...) thay vì post.comments.create (...)).

post.comments.size - Điều này hoạt động như một sự kết hợp của hai tùy chọn trước đó. Nếu bộ sưu tập đã được tải, nó sẽ trả về độ dài của nó giống như gọi #length. Nếu nó chưa được tải, nó giống như gọi #count.

Ngoài ra tôi có một kinh nghiệm cá nhân:

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

2

Chúng tôi có một số cách để tìm hiểu có bao nhiêu phần tử trong một mảng như thế nào .length, .count.size. Tuy nhiên, tốt hơn là sử dụng array.sizehơn là array.count. Bởi vì .sizehiệu suất tốt hơn.


1

Thêm nhiều hơn để trả lời Mark Byers. Trong Ruby phương thức array.sizelà một bí danh cho phương thức Array # length . Không có sự khác biệt về kỹ thuật trong việc sử dụng bất kỳ phương pháp nào trong hai phương pháp này. Có thể bạn sẽ không thấy bất kỳ sự khác biệt trong hiệu suất là tốt. Tuy nhiên, array.countcũng thực hiện công việc tương tự nhưng với một số chức năng bổ sung Array # Count

Nó có thể được sử dụng để có được tổng số phần tử không dựa trên một số điều kiện. Đếm có thể được gọi theo ba cách:

Mảng # đếm # Trả về số phần tử trong Mảng

Mảng # đếm n # Trả về số phần tử có giá trị n trong Mảng

Mảng # đếm {| i | i.even?} Trả về số lượng dựa trên điều kiện được gọi trên mỗi mảng phần tử

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

Ở đây cả ba phương pháp đều làm cùng một công việc. Tuy nhiên đây là nơi countthú vị.

Hãy để chúng tôi nói, tôi muốn tìm xem có bao nhiêu phần tử mảng có giá trị 2

array.count 2    # => 3

Mảng có tổng cộng ba phần tử với giá trị là 2.

Bây giờ, tôi muốn tìm tất cả các phần tử mảng lớn hơn 4

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

Mảng có tổng số 6 phần tử lớn hơn 4.

Tôi hy vọng nó cung cấp một số thông tin về countphương pháp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.