至少在 Ruby 1.9.3 中,Enumerable
对象没有 length
属性。这是为什么?
Enumerable
类有一个count
方法,通常会返回枚举对象的直观“长度”。
但为什么不能称之为“长度”呢?因为它的操作方式完全不同。在 Ruby 的内置数据结构中(如Array
和Hash
),length
只是检索预计算的数据结构大小,它应该立即返回。
然而,在Enumerable#count
中,它无法知道其操作的结构类型,因此没有快速、聪明的方法来获取枚举对象的大小(这是因为Enumerable
是一个模块,并且可以包含在任何类中)。它获取枚举对象的大小的唯一方法就是对其进行枚举并计数。对于无限枚举,count
将(适当地)永远循环并永远不会返回。
Enumerator
有一个size
方法,并且对于无限枚举,它的工作方式符合预期:loop.size #=> Infinity
。 - Stefanenum = [1,2,3].to_enum; enum.size #=> nil
。 - Cary Swoveland[1,2,3].each.size #=> 3
- Stefan枚举对象并不保证有长度 - 混入 Enumerable 的唯一要求是它响应 #each
,这使其返回系列中的下一个项,以及 #<=>
,它允许比较可枚举提供的值。像 #sort
这样的方法将在排序过程中枚举整个集合,但可能事先不知道集合的范围。请考虑:
class RandomSizeEnumerable
include Enumerable
def each
value = rand 1000
while value != 500
yield value
value = rand 1000
end
end
# Not needed for this example, but included as a part of the Enumerable "interface".
# You only need this method if #max, #min, or #sort are used on this class.
def <=>(a, b)
a <=> b
end
end
该可枚举对象将被调用,直到迭代器生成值“500”,这将导致停止枚举。结果集被收集并排序。然而,在这种情况下,#length
方法是没有意义的,因为在迭代器被耗尽之前无法确定长度!
我们可以对像#sort
这样返回数组的结果调用#length
:
p RandomSizeEnumerable.new.sort.length # 321
p RandomSizeEnumerable.new.sort.length # 227
p RandomSizeEnumerable.new.sort.length # 299
传统上,当长度已知且可以在常数时间内返回时,使用#length
,而当长度可能事先不知道并需要通过迭代结果集进行计算时,则倾向于使用#count
(有时也使用#size
),这样会花费线性时间。如果你需要获取 Enumerable 提供的结果集大小,请尝试使用#count
,而不是 。.to_a.length
#count
的时间复杂度为O(n),而 #length
的时间复杂度为O(1)。文档和提供的示例清楚地说明了这一点,因为您必须迭代可枚举对象才能发现需要多少次调用才能终止。 - Chris Healdcount
仍然比 to_a.length
更受欢迎。 - MaxEnumerable
方法时才需要定义<=>
。有许多Enumerable
方法(例如count
)不使用<=>
。 - Cary SwovelandEnumerable
并不是一个类,而是一个模块 - 一个包含跨越多个类使用的横切功能的集合。
例如,Array
、Set
和Hash
都include
它 - 您可以在它们上调用任何Enumerable
方法。
Enumerable
值得注意的是,它对“主机”类的要求非常少。您只需要定义each
方法和include Enumerable
,就可以免费获得所有这些方法!例如:
class CountUntil
def initialize(number)
@number = number
end
include Enumerable
def each
current = 0
while current < @number
yield current
current += 1
end
end
end
# Usage:
CountUntil.new(10).map { |n| n * 5 }
# => [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]
Enumerable
模块的任何类吗?这样的类(以及其他类)都有一个length
(又名size
)方法。 - Cary SwovelandEnumerable#count
方法。 - cremnolength
方法”时,我没有提到我指的是内置类,但现在我甚至不确定。是否有人知道一个混入了Enumerable
但没有length
方法的内置类? - Cary Swovelandsize
,例如,Range#size。 :-) - Cary SwovelandInteger
、Numerica
、Proc
、CSV
、Matrix
),也许定义length
的类是个例外而不是规则。 - Cary Swoveland