为什么Enumerable在Ruby中没有length属性?
Why does Enumerable not have a length attribute in Ruby?
至少在Ruby 1.9.3 中,Enumerable
对象没有length
属性。这是为什么?
不保证可枚举的长度 - 混合可枚举的对象的唯一要求是它响应 #each
,这导致它 return 系列中的下一个项目, 和 #<=>
允许比较可枚举提供的值。 #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
,因为它们 return 是一个数组,但是:
p RandomSizeEnumerable.new.sort.length # 321
p RandomSizeEnumerable.new.sort.length # 227
p RandomSizeEnumerable.new.sort.length # 299
通常,#length
用于长度已知且可以在常数时间内returned,而#count
(有时#size
)往往是当可能无法提前知道长度并且需要通过迭代结果集(因此,需要线性时间)来计算长度时使用。如果您需要 Enumerable 提供的结果集的大小,请尝试使用 .to_a.length
#count
.
Enumerable
并不是真正的 class,它是一个模块 - 多个 classes 使用的横切功能的集合。
例如,Array
、Set
和 Hash
都是 include
它 - 您可以对它们调用任何 Enumerable
方法。
Enumerable
值得注意的是它需要很少的 "host" class。您需要做的就是定义 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]
如您所见,我从未定义 CountUntil#map
,但我通过包含 Enumerable
.
免费获得了它
解决您关于 length
的问题:并非所有包含 Enumerable
的 class 都定义了长度,尽管大多数都定义了长度。例如,Enumerator
可用于创建无限流。
Enumerable有count
方法,通常是枚举的直观"length"。
但为什么不叫它"length"呢?好吧,因为它的运作方式非常不同。在 Ruby 的内置数据结构中,如 Array
和 Hash
,length
只是检索数据结构的预先计算的大小。它应该总是立即 return。
然而,对于 Enumerable#count
,它无法知道它在哪种结构上运行,因此没有快速、巧妙的方法来获取枚举的大小(这是因为 Enumerable
是一个模块,可以包含在任何 class) 中。它获得枚举大小的唯一方法是实际枚举它并在进行时进行计数。对于无限枚举,count
将(适当地)永远循环并且永远不会 return.
至少在Ruby 1.9.3 中,Enumerable
对象没有length
属性。这是为什么?
不保证可枚举的长度 - 混合可枚举的对象的唯一要求是它响应 #each
,这导致它 return 系列中的下一个项目, 和 #<=>
允许比较可枚举提供的值。 #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
,因为它们 return 是一个数组,但是:
p RandomSizeEnumerable.new.sort.length # 321
p RandomSizeEnumerable.new.sort.length # 227
p RandomSizeEnumerable.new.sort.length # 299
通常,#length
用于长度已知且可以在常数时间内returned,而#count
(有时#size
)往往是当可能无法提前知道长度并且需要通过迭代结果集(因此,需要线性时间)来计算长度时使用。如果您需要 Enumerable 提供的结果集的大小,请尝试使用 .to_a.length
#count
.
Enumerable
并不是真正的 class,它是一个模块 - 多个 classes 使用的横切功能的集合。
例如,Array
、Set
和 Hash
都是 include
它 - 您可以对它们调用任何 Enumerable
方法。
Enumerable
值得注意的是它需要很少的 "host" class。您需要做的就是定义 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]
如您所见,我从未定义 CountUntil#map
,但我通过包含 Enumerable
.
解决您关于 length
的问题:并非所有包含 Enumerable
的 class 都定义了长度,尽管大多数都定义了长度。例如,Enumerator
可用于创建无限流。
Enumerable有count
方法,通常是枚举的直观"length"。
但为什么不叫它"length"呢?好吧,因为它的运作方式非常不同。在 Ruby 的内置数据结构中,如 Array
和 Hash
,length
只是检索数据结构的预先计算的大小。它应该总是立即 return。
然而,对于 Enumerable#count
,它无法知道它在哪种结构上运行,因此没有快速、巧妙的方法来获取枚举的大小(这是因为 Enumerable
是一个模块,可以包含在任何 class) 中。它获得枚举大小的唯一方法是实际枚举它并在进行时进行计数。对于无限枚举,count
将(适当地)永远循环并且永远不会 return.