Кількість, розмір, довжина… занадто багато варіантів у Ruby?


140

Я не можу знайти остаточну відповідь на це, і я хочу переконатися, що я розумію це до "n-го рівня" :-)

    a = {"a" => "Привіт", "b" => "Світ"}
    a.count # 2
    а.розмір №2
    a. довжина №2

    a = [10, 20]
    a.count # 2
    а.розмір №2
    a. довжина №2

Отже, що використовувати? Якщо я хочу знати, чи є у елемента більше, ніж один елемент, то це, мабуть, не має значення, але я хочу переконатися, що я розумію реальну різницю. Це стосується і масивів. Я отримую однакові результати.

Також я розумію, що кількість / розмір / довжина мають різні значення з ActiveRecord. Мене в основному цікавлять чисті Ruby (1,92) зараз, але якщо хтось хоче прислухатись до різниці AR, це також буде оцінено.

Дякую!


5
Явище, з яким ви стикалися, іноді називають TMTOWTDI : Існує більше, ніж один спосіб зробити це. Цей слоган походить від спільноти Perl, і Perl є одним із впливів на Рубі.
Ендрю Грімм

це зазвичай псевдоніми один для одного - вони роблять те саме. Існує також один метод, про який слід також пам’ятати:, 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( вихідного коду ), яка перебирає всі елементи та рахує їх по одному.

Як правило, я б радив використовувати length(або його псевдонім size), а не, countякщо ви хочете знати, скільки елементів усього є.


Щодо ActiveRecord, з іншого боку, є важливі відмінності. перевірити цю публікацію:


10

Існує вирішальна відмінність для додатків, які використовують з'єднання бази даних.

Коли ви використовуєте багато ORM (ActiveRecord, DataMapper тощо), загальне розуміння полягає в тому, що .size генерує запит, який запитує всі елементи з бази даних ('select * from mytable') і надасть вам кількість елементів в результаті, тоді як .count генерує один запит ('select count (*) from mytable'), який значно швидше.

Оскільки ці ОРМ настільки поширені, я слідую принципу найменшого здивування. Як правило, якщо у мене вже є щось у пам'яті, я використовую .size, і якщо мій код генерує запит до бази даних (або зовнішньої служби через API), я використовую .count.


1
Щось з цим врахувати counter_cache. Якщо у вас є таблиця, fooі вона має_мало bar, ви матимете стовпець у fooімені, bars_countякий оновлюється будь-коли, коли barбуде створено / знищено a . Використання foo.bars.size- це те, що перевіряє цей стовпець (без фактичного запиту bars). foo.bars.countробить власне запит, який би перебив ціль кешу.
Дудо

7

У більшості випадків (наприклад, масив або рядок ) sizeє псевдонімом для length.

countзазвичай надходить з Unumerable і може приймати необов'язковий блок предикатів. Таким чином enumerable.count {cond}є [приблизно] (enumerable.select {cond}).length- він, звичайно, може обійти проміжну структуру, оскільки він просто потребує підрахунку відповідних предикатів.

Примітка: Я не впевнений , що якщо count сили оцінки перерахування , якщо блок не зазначено або коротке замикання на , lengthякщо це можливо.

Редагувати (і завдяки відповіді Марка!): count Без блоку (принаймні для масивів) не змушує оцінювати. Я вважаю, що без формальної поведінки це "відкрито" для інших реалізацій, якщо примусово оцінювати без предиката будь-коли навіть справді має сенс.


5

Я знайшов гарне програмне забезпечення на http://blog.hasmanythrough.com/2008/2/27/count-length-size

У ActiveRecord є кілька способів дізнатися, скільки записів є в асоціації, і є деякі тонкі відмінності в тому, як вони працюють.

post.comments.count - визначте кількість елементів із запитом SQL COUNT. Ви також можете вказати умови для підрахунку лише підмножини пов'язаних елементів (наприклад: умови => {: автор_імен => "Джош"}). Якщо ви встановите кеш-лічильник для асоціації, #count поверне це кешоване значення замість виконання нового запиту.

post.comments.length - Це завжди завантажує вміст асоціації в пам'ять, а потім повертає кількість завантажених елементів. Зауважте, що це не примусить оновити, якщо асоціація була раніше завантажена, а потім нові коментарі були створені іншим способом (наприклад, Comment.create (...) замість post.comments.create (...)).

post.comments.size - це працює як поєднання двох попередніх варіантів. Якщо колекція вже завантажена, вона поверне свою довжину так само, як і виклик #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

Додавання ще до відповіді Марка Байєра. У Ruby метод array.sizeє псевдонімом методу Array # length . Немає технічної різниці у використанні будь-якого з цих двох методів. Можливо, ви також не побачите різниці в продуктивності. Тим НЕ менше, array.countтакож виконує ту ж роботу , але з деякими додатковими функціональність масиву підрахунку #

Він може бути використаний для отримання загальної кількості елементів на основі певної умови. Графа можна назвати трьома способами:

Масив # count # Повертає кількість елементів у масиві

Масив # count n # Повертає кількість елементів, що мають значення n у масиві

Масив # 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

Тут усі три методи роблять одну і ту ж роботу. Однак тут countстає цікаво.

Скажімо, я хочу знайти, скільки елементів масиву містить масив зі значенням 2

array.count 2    # => 3

Масив містить усього три елементи зі значенням 2.

Тепер я хочу знайти всі елементи масиву більше 4

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

У масиві є 6 елементів, що> більше 4.

Я сподіваюся, що це дає деяку інформацію про countметод.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.