鲁比:更好理解.to_enum



我一直在读这个:

https://docs.ruby-lang.org/en/2.4.0/Enumerator.html

我试图理解为什么有人会使用.to_enum,我的意思是,这与仅仅使用数组有什么不同?我明白了:扫描被传递给了它,但你还能传递给它什么其他论点呢?

为什么不在下面的情况下使用.scan?关于如何更好地理解.to_enum,有什么建议吗?

"Hello, world!".scan(/w+/)                     #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan, /w+/).to_a      #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan).each(/w+/).to_a #=> ["Hello", "world"]

数组必然是内存中的结构。一个包含大量条目的数组会占用大量内存。

为了把这放在上下文中,这里有一个例子,找到所有";回文";介于1和1000000之间的数字:

# Create a large array of the numbers to search through
numbers = (1..1000000).to_a
# Filter to find palindromes
numbers.select do |i|
is = i.to_s
is == is.reverse
end

尽管只有1998个这样的数字,但需要创建一个完整的100万数组,然后进行筛选,然后一直保存到垃圾收集。

枚举器根本不一定会占用任何内存,也不会以相应的方式占用内存。这更有效:

# Uses an enumerator instead
numbers = (1..1000000).to_enum
# Filtering code looks identical, but behaves differently
numbers.select do |i|
is = i.to_s
is == is.reverse
end

您甚至可以通过制作自定义枚举器:来更进一步

palindromes = Enumerator.new do |y|
1000000.times do |i|
is = (i + 1).to_s
y << i if (is == is.reverse)
end
end

这个甚至不需要过滤,它只会发出回文数字。

枚举器还可以做其他事情,比如长度为无限,而数组必须是有限的。当您想要筛选并获取第一个N匹配条目时,无限枚举器可能很有用,比如本例中的

# Open-ended range, new in Ruby 2.6. Don't call .to_a on this!
numbers = (1..).to_enum
numbers.lazy.select do |i|
is = i.to_s
is == is.reverse
end.take(1000).to_a

这里使用.lazy意味着它执行select,然后对每个条目过滤take,直到take方法满意为止。如果删除lazy,它将尝试并评估它的每个阶段,直到完成,这在无限枚举器上是永远不会发生的。

最新更新