为什么Enumerable在Ruby中没有length属性?

时间:2015-03-03 18:17:19

标签: ruby enumerable

至少在Ruby 1.9.3中,Enumerable个对象没有length属性。

据我所知,任何Enumerable都是一个集合,sortfind_index等方法证明了这一点。

一个集总是有一个明确定义的长度(......对吗?),那为什么这不是一个属性?

3 个答案:

答案 0 :(得分:10)

Enumerable有count方法,通常是枚举的直观“长度”。

但为什么不把它称为“长度”?好吧,因为它的运作方式非常不同。在Ruby的内置数据结构中,如ArrayHashlength只是检索数据结构的预先计算的大小。它应该总是立即返回。

然而,对于Enumerable#count,它无法知道它正在运行什么类型的结构,因此没有快速,巧妙的方法来获得枚举的大小(这是因为Enumerable是一个模块,可以包含在任何类中)。获取枚举大小的唯一方法是实际枚举它并按计算进行计数。对于无限枚举,count将(适当地)循环永远,永不返回。

答案 1 :(得分:2)

不能保证Enumerables有长度 - 对于Enumerable混入的对象的唯一要求是它响应#each,这会导致它返回系列中的下一个项目,{{1}这允许比较可枚举的值。像#<=>这样的方法将在排序过程中枚举整个集合,但可能不会提前知道集合的边界。考虑:

#sort

这个枚举将被调用,直到迭代器生成值&#34; 500&#34;,这将导致它停止枚举。收集并排序结果集。但是,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 方法在此上下文中没有意义,因为在迭代器耗尽之前,长度是不可知的!

我们可以就#length之类的结果调用#length,因为它们会返回一个数组:

#sort

传统上,当长度已知并且可以在恒定时间内返回时使用p RandomSizeEnumerable.new.sort.length # 321 p RandomSizeEnumerable.new.sort.length # 227 p RandomSizeEnumerable.new.sort.length # 299 ,而当长度可能不是时,往往会使用#length(有时#count)提前知道并且需要通过迭代结果集来计算(因此,采用线性时间)。如果您需要Enumerable提供的结果集的大小,请尝试使用 #size .to_a.length

答案 2 :(得分:0)

Enumerable实际上不是一个类,它是一个模块 - 多个类使用的交叉功能的集合。

例如,ArraySetHash所有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]

正如您所看到的,我从未定义过CountUntil#map,但我免费提供Enumerable

要解决有关length的问题:并非所有包含Enumerable的类都定义了长度,即使大多数类都有。例如,Enumerator可用于创建无限流。