数量、大小、长度……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】:

对于数组和哈希,sizelength 的别名。它们是同义词,做的事情完全相同。

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)sizelength别名

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 中有太多选择?的主要内容,如果未能解决你的问题,请参考以下文章

每行中有太多空字段会影响 PostgreSQL 中的搜索性能吗?

MySQL 中各种对象的大小长度限制

Android 中的长度单位pxdpsp

因为有太多的无奈,我选择了逞强

机器学习训练和测试数据拆分方法

如何使循环计算更快