Граф, размер, длина... слишком много вариантов в Ruby?

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

    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

Так что использовать? Если я хочу знать, имеет ли более одного элемента, то это, похоже, не имеет значения, но я хочу убедиться, что я понимаю реальную разницу. Это относится и к массивам. Я получаю те же результаты.

Кроме того, я понимаю, что count/size/length имеют разные значения с помощью ActiveRecord. Меня больше всего интересует чистый Ruby (1.92) прямо сейчас, но если кто-то хочет перекликаться с разницей AR, это тоже будет оценено.

Спасибо!

Ответ 1

Для массивов и хешей 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, с другой стороны, существуют важные различия. прочитайте это сообщение:

Ответ 2

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

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

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

Ответ 3

В большинстве случаев (например, Array или String) size является псевдонимом для length.

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

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

Изменить (и спасибо Mark ответ!): count без блока (по крайней мере для массивов) не заставляет оценивать. Я полагаю, что без формального поведения он "открыт" для других реализаций, если бы принудительная оценка без предиката никогда даже не имела смысла.

Ответ 4

Я нашел хорошее приложение в 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 !

Ответ 5

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

Ответ 6

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

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

Массив # count # Возвращает количество элементов в массиве

Array # count n # Возвращает число элементов, имеющих значение n в массиве

Массив # Количество {| я | i? e?? Возвращает количество, основанное на условии, вызванном для каждого массива элементов

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.