数数,大小,长度... Ruby 里有太多选择了吗?

我似乎找不到这个问题的确切答案,我想确保我理解到“非 h 级”: -)



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 是否有不止一个元素,那么这似乎并不重要,但我想确保我理解了真正的区别。这也适用于数组。我得到了同样的结果。

此外,我意识到 count/size/length 对 ActiveRecord 有不同的含义。我现在最感兴趣的是纯 Ruby (1.92) ,但如果有人想加入到 AR 带来的不同中来,我也会很感激的。

谢谢!

74145 次浏览

对于数组和散列来说,sizelength的别名。它们是同义词,完全相同。

count 通用性更强——它可以接受一个元素或谓词,并只计算匹配的项。

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

不要提供一个参数来计数的情况下,它与调用 length 的效果基本相同。不过,可能存在性能差异。

我们可以从 数组源代码中看到,它们做的几乎完全一样。下面是实现 array.length的 C 代码:

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))

另一方面,Hash (源代码)似乎没有实现它们自己的优化版本的 count,所以使用了来自 Enumerable(源代码)的实现,它迭代所有元素并逐个计数。

通常,如果你想知道一共有多少个元素,我建议使用 length(或者它的别名 size)而不是 count


关于 ActiveRecord,另一方面,它和 有很大的不同。看看这篇文章:

在大多数情况下(例如 数组绳子) ,sizelength化名

count通常来自 数不胜数,可以采用一个可选的谓词块。因此,enumerable.count {cond}就是[大致] (enumerable.select {cond}).length——它当然可以绕过中间结构,因为它只需要匹配谓词的计数。

注意: 如果没有指定块,我不确定 count 力量是否对枚举进行求值,或者如果可能的话,它是否短路到 length

编辑(并感谢马克的回答!): count 没有任何障碍(至少对于数组) 没有强制评估。我认为没有正式的行为,它对其他实现是“开放的”,如果强制没有谓词的评估甚至真的有意义的话。

对于使用数据库连接的应用程序来说,有一个关键的区别。

当您使用许多 ORM (ActiveRecord、 DataMapper 等)时,一般的理解是。Size 将生成一个查询,请求数据库中的所有项(‘ select * from mytable’) ,然后给出结果项的数量,而。Count 将生成一个查询(‘ select count (*) from mytable’) ,这样会快得多。

因为这些 ORM 非常普遍,所以我遵循了这个最小惊讶原则。一般来说,如果我已经在内存中有了一些东西,那么我就使用。如果我的代码将生成对数据库(或通过 API 的外部服务)的请求,我使用。计数。

我在 http://blog.hasmanythrough.com/2008/2/27/count-length-size找到了一个不错的答案

在 ActiveRecord 中,有几种方法可以查找有多少条记录 是有联系的,而且有一些细微的差别 它们有用。

Count-使用 SQL 确定元素的数量 还可以指定条件,以便只计算 相关联的元素(例如条件 = > { : author _ name = >) })如果在关联上设置了一个计数器缓存,# count 将返回该缓存值,而不执行新查询。

Length-这总是加载 关联到内存中,然后返回加载的元素数。 请注意,如果关联已经 之前加载的,然后通过另一个创建新的注释 方法(例如,Comment.create (...)而不是 post.comms.create (...))。

Size-这是前面两个的组合 如果集合已经加载,它将返回其 Length 就像调用 # length 一样。如果它还没有被加载,那么它是 比如叫 # count。

此外,我还有一个个人经历:

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

为马克 · 拜尔斯的回答增添更多内容。在 Ruby 中,方法 array.size数组 # 长度方法的别名。使用这两种方法中的任何一种都没有技术上的区别。可能您也不会看到任何性能上的差异。然而,array.count也做同样的工作,但一些额外的功能 Array # count

根据一定的条件,可以得到元素的全无。计数可以通过三种方式调用:

Array # count # 返回 Array 中的元素数

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方法的信息。

我们有几种方法来确定一个数组中有多少个元素,如 .length.count.size。但是,最好使用 array.size而不是 array.count。因为 .size的性能更好。