数量、大小、长度……Ruby 中有太多选择?
Posted
技术标签:
【中文标题】数量、大小、长度……Ruby 中有太多选择?【英文标题】:Count, size, length...too many choices in Ruby? 【发布时间】:2011-05-31 20:22:15 【问题描述】:我似乎无法找到明确的答案,我想确保我理解到“第 n 级”:-)
a = "a" => "你好", "b" => "世界" a.count #2 a.尺寸#2 a.长度#2 a = [ 10, 20 ] a.count #2 a.尺寸#2 a.长度#2那么使用哪个?如果我想知道 a 是否有多个元素,那么这似乎无关紧要,但我想确保我了解真正的区别。这也适用于数组。我得到了相同的结果。
另外,我意识到计数/大小/长度与 ActiveRecord 有不同的含义。我现在对纯 Ruby (1.92) 最感兴趣,但如果有人想了解 AR 带来的不同,我也将不胜感激。
谢谢!
【问题讨论】:
您遇到的现象有时被称为TMTOWTDI:有不止一种方法可以做到这一点。这个口号来自 Perl 社区,Perl 是对 Ruby 的影响之一。 这些通常是彼此的别名——它们的作用相同。您还应该记住一种方法:Array#nitems
,它返回数组中非 NIL 项的数量。但这在 Ruby 1.9 中不再可用
【参考方案1】:
对于数组和哈希,size
是 length
的别名。它们是同义词,做的事情完全相同。
count
更通用——它可以接受一个元素或谓词,并且只计算那些匹配的项目。
> [1,2,3].count|x| x > 2
=> 1
如果你不提供一个参数来计算它与调用长度的效果基本相同。但可能存在性能差异。
我们可以从source code for Array 看到他们做几乎完全相同的事情。下面是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))
。
另一方面,哈希 (source code) 似乎没有实现他们自己的 count
优化版本,因此使用了来自 Enumerable
(source code) 的实现,它遍历所有元素和计数他们一个接一个。
如果您想知道总共有多少个元素,我建议使用length
(或其别名size
)而不是count
。
另一方面,关于 ActiveRecord,存在 重要的区别。看看这篇文章:
Counting ActiveRecord associations: count, size or length?【讨论】:
【参考方案2】:对于使用数据库连接的应用程序来说,有一个关键的区别。
当您使用许多 ORM(ActiveRecord、DataMapper 等)时,一般的理解是 .size 将生成一个查询,该查询从数据库中请求所有项目('select * from mytable'),然后为您提供结果的项目数,而 .count 将生成一个查询('select count(*) from mytable'),这要快得多。
因为这些 ORM 如此普遍,所以我遵循最小惊讶原则。一般来说,如果我的内存中已经有一些东西,那么我会使用 .size,如果我的代码会生成对数据库(或通过 API 的外部服务)的请求,我会使用 .count。
【讨论】:
需要考虑的是counter_cache
。如果有一个表foo
,并且它有_many bar
,那么您将在foo
中有一个名为bars_count
的列,该列会在创建/销毁bar
时随时更新。使用foo.bars.size
是检查该列的内容(实际上不查询任何bars
)。 foo.bars.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.cmets.count - 使用 SQL 确定元素的数量 COUNT 查询。您还可以指定条件以仅计算 相关的元素(例如 :conditions => :author_name => “乔希”)。如果在关联上设置计数器缓存,#count 将返回该缓存值,而不是执行新查询。
post.cmets.length - 这总是加载 关联到内存中,然后返回加载的元素数。 请注意,如果关联已被取消,则不会强制更新 以前加载,然后通过另一个创建新的 cmets 方式(例如 Comment.create(...) 而不是 post.cmets.create(...))。
post.cmets.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 # 返回数组中的元素个数
Array#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
方法的信息。
【讨论】:
以上是关于数量、大小、长度……Ruby 中有太多选择?的主要内容,如果未能解决你的问题,请参考以下文章