Количество, размер, длина ... слишком много вариантов в Ruby? - PullRequest
138 голосов
/ 29 декабря 2010

Я не могу найти однозначного ответа на этот вопрос, и я хочу убедиться, что я понимаю это до "n'th level": -)


    a = { "a" => "Hello", "b" => "World" }
    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, это также будет оценено.

Спасибо!

Ответы [ 6 ]

192 голосов
/ 29 декабря 2010

Для массивов и хэшей size - псевдоним для length. Они являются синонимами и делают одно и то же.

count более универсален - он может принимать элемент или предикат и считать только те элементы, которые соответствуют.

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

В случае, когда вы не предоставляете параметр для подсчета, он в основном имеет тот же эффект, что и длина вызова. Хотя может быть разница в производительности.

Из исходного кода для массива мы видим, что они делают почти одно и то же. Вот код 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 ( исходный код ) used, который перебирает все элементы и считает их один за другим.

В общем, я бы посоветовал использовать length (или его псевдоним size) вместо count, если вы хотите узнать, сколько всего элементов в целом.


Что касается ActiveRecord, с другой стороны, имеет важных отличий. проверить этот пост:

10 голосов
/ 29 декабря 2010

Существует принципиальная разница для приложений, которые используют соединения с базой данных.

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

Поскольку эти ОРМ настолько распространены, я следую принципу наименьшего удивления. В общем, если у меня уже есть что-то в памяти, я использую .size, и если мой код сгенерирует запрос к базе данных (или внешней службе через API), я использую .count.

7 голосов
/ 29 декабря 2010

В большинстве случаев (например, Массив или Строка ) size - это псевдоним для length.

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

Примечание: я не уверен, если count принудительно вычисляет перечисление, если блок не указан или если он, если возможно, замыкается на length.

Редактировать (и благодаря ответу Марка!): count без блока (по крайней мере, для массивов) не не вызывает оценку.Я предполагаю, что без формального поведения это «открыто» для других реализаций, если принудительное вычисление без предиката вообще когда-либо действительно имеет смысл.

5 голосов
/ 20 ноября 2011

Я нашел хороший ответ на http://blog.hasmanythrough.com/2008/2/27/count-length-size

В ActiveRecord есть несколько способов узнать, сколько записей в ассоциации, и есть некоторые тонкие различия в том, как они работают.

post.comments.count - определяет количество элементов с помощью запроса SQL COUNT.Вы также можете указать условия для подсчета только подмножества связанных элементов (например, условия => {: author_name => "josh"}).Если вы установили кэш счетчика для ассоциации, #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 голосов
/ 06 апреля 2016

У нас есть несколько способов узнать, сколько элементов в массиве, таких как .length, .count и .size. Однако лучше использовать array.size, а не array.count. Потому что .size лучше по производительности.

1 голос
/ 15 марта 2016

Добавление большего к ответу Марка Байерса.В Ruby метод array.size является псевдонимом Array # length метод.Нет никакой технической разницы в использовании любого из этих двух методов.Возможно, вы не увидите никакой разницы в производительности.Тем не менее, array.count также выполняет ту же работу, но с некоторыми дополнительными функциями Array # count

Он может использоваться для получения общего количества элементов на основе некоторого условия.Счет может быть вызван тремя способами:

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

Здесь все три метода выполняют одну и ту же работу.Однако вот где count становится интересным.

Допустим, я хочу выяснить, сколько элементов массива содержит массив со значением 2

array.count 2    # => 3

В массиве всего три элемента со значением 2.

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

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

В массиве всего 6 элементов, которые> чем 4.

Надеюсь, это даст некоторую информацию о методе count.

...