数量,大小,长度……在Ruby中有太多选择?


140

我似乎找不到确切的答案,我想确保自己了解“ n级” :-)

    a = {“ a” =>“ Hello”,“ b” =>“世界”}
    a.count#2
    a。大小#2
    长度#2

    a = [10,20]
    a.count#2
    a。大小#2
    长度#2

那么该使用哪个呢?如果我想知道a是否具有多个元素,那么这似乎无关紧要,但是我想确保自己了解真正的区别。这也适用于数组。我得到相同的结果。

另外,我认识到ActiveRecord的count / size / length具有不同的含义。我现在对纯Ruby(1.92)最为感兴趣,但是如果有人想了解一下AR的不同之处,那也将不胜感激。

谢谢!


5
您遇到的现象有时称为TMTOWTDI:有多种方法可以做到。这个口号来自Perl社区,Perl是对Ruby的影响之一。
安德鲁·格林

这些通常是彼此的别名-它们也一样。您还应该记住一种方法:Array#nitems,它返回数组中非NIL项的数量。但这在Ruby 1.9中不再可用
Tilo

Answers:


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将生成单个查询(“来自mytable的select count(*)”),该查询要快得多。

因为这些ORM非常流行,所以我遵循最小惊讶原则。通常,如果内存中已经有东西,则使用.size,如果我的代码将生成对数据库(或通过API的外部服务)的请求,则使用.count。


1
需要考虑的是counter_cache。如果有一个表,foo它具有has_many bar,则将在foonamed bars_count中有一个列,该列在bar创建或销毁a时会更新。使用foo.bars.size会检查该列(无需实际查询bars)。foo.bars.count进行实际的查询,这会破坏缓存的目的。
Dudo 2014年

7

在大多数情况下(例如阵列字符串size是一个别名length

count通常来自Enumerable,并且可以使用可选的谓词块。enumerable.count {cond}[大致] 因此(enumerable.select {cond}).length,它当然可以绕过中间结构,因为它只需要匹配谓词的数量即可。

注意:如果不确定未指定该块,或者如果可能的话,它是否短路,则不确定是否count 强制对枚举进行评估length

编辑(并感谢Mark的回答!): count 没有块(至少对于Arrays)不会强制求值。我认为,如果没有正式的行为,即使没有谓词的情况下强制进行评估,它对于其他实现也是“开放的”。


5

我在http://blog.hasmanythrough.com/2008/2/27/count-length-size找到了一个很好的软件

在ActiveRecord中,有几种方法可以找出一个关联中有多少条记录,并且它们的工作方式也有细微的差别。

post.comments.count-使用SQL COUNT查询确定元素数。您还可以指定条件,以仅计算关联元素的子集(例如:conditions => {: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

我们有几种方法可以找出数组中有多少个元素,例如 .length.count.size。但是,最好使用array.size而不是array.count。因为.size性能更好。


1

为Mark Byers答案添加更多内容。在Ruby中,该方法array.sizeArray#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方法的信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.