在Ruby Array Class文档中,我经常发现:
如果没有给出阻止,则返回枚举器。
为什么我不会将块传递给#map
?我的用处是什么:
[1,2,3,4].map
而不是:
[1,2,3,4].map{ |e| e * 10 } # => [10, 20, 30, 40]
有人能告诉我一个使用这个枚举器的非常实用的例子吗?
答案 0 :(得分:7)
好问题。
如果我们想要使用创建的枚举器执行多项操作,该怎么办?我们现在不想处理它,因为这意味着我们可能需要稍后创建另一个?
my_enum = %w[now is the time for all good elves to get to work].map # => #<Enumerator: ["now", "is", "the", "time", "for", "all", "good", "elves", "to", "get", "to", "work"]:map>
my_enum.each(&:upcase) # => ["NOW", "IS", "THE", "TIME", "FOR", "ALL", "GOOD", "ELVES", "TO", "GET", "TO", "WORK"]
my_enum.each(&:capitalize) # => ["Now", "Is", "The", "Time", "For", "All", "Good", "Elves", "To", "Get", "To", "Work"]
答案 1 :(得分:4)
当没有给出块时返回enumerable
的功能主要用于将可枚举类中的函数链接在一起时。像这样:
abc = %w[a b c]
p abc.map.with_index{|item, index| [item, index]} #=> [["a", 0], ["b", 1], ["c", 2]]
编辑:
我认为我对这种行为的理解有点过于局限,无法正确理解Ruby的内部工作原理。我认为最重要的是要注意参数的传递方式与Procs相同。因此,如果传入一个数组,它将自动'splatted'(这个更好的词?)。我认为获得理解的最好方法是使用一些简单的函数返回枚举并开始试验。
abc = %w[a b c d]
p abc.each_slice(2) #<Enumerator: ["a", "b", "c", "d"]:each_slice(2)>
p abc.each_slice(2).to_a #=> [["a", "b"], ["c", "d"]]
p abc.each_slice(2).map{|x| x} #=> [["a", "b"], ["c", "d"]]
p abc.each_slice(2).map{|x,y| x+y} #=> ["ab", "cd"]
p abc.each_slice(2).map{|x,| x} #=> ["a", "c"] # rest of arguments discarded because of comma.
p abc.each_slice(2).map.with_index{|array, index| [array, index]} #=> [[["a", "b"], 0], [["c", "d"], 1]]
p abc.each_slice(2).map.with_index{|(x,y), index| [x,y, index]} #=> [["a", "b", 0], ["c", "d", 1]]
答案 2 :(得分:4)
Ruby核心库(Enumerator
,Array
)和标准库({{}中的Hash
和大多数†其他数据结构之间的主要区别1}},Set
)是SortedSet
可以无限。您不能拥有Enumerator
所有偶数或零流或所有素数,但您绝对可以拥有Array
:
Enumerator
那么,你可以用这样的evens = Enumerator.new do |y|
i = -2
y << i += 2 while true
end
evens.take(10)
# => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
zeroes = [0].cycle
zeroes.take(10)
# => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
做什么?好吧,三件事,基本上。
Enumerator
混合在Enumerator
中。因此,您可以使用所有Enumerable
方法,例如Enumerable
,map
,inject
,all?
,any?
,none?
, select
等等。请注意,reject
可能是无限的,而Enumerator
会返回map
,因此尝试Array
无限map
可能会产生无限大Enumerator
Array
并且花费无限的时间。
有一些包装方法以某种方式“丰富”Enumerator
并返回一个新的Enumerator
。例如,Enumerator#with_index
向块添加“循环计数器”,Enumerator#with_object
添加备忘录对象。
您可以使用Enumerator
,就像您在其他语言中使用Enumerator#next
进行外部迭代一样,使用Enumerator
方法,它会为您提供下一个值(并移动raise
1}}转发)或StopIteration
Enumerator
例外如果(1..1.0/0)
是有限的并且您已到达终点。
†例如,无限范围:{{1}}
答案 3 :(得分:2)
除了hirolau的回答之外,还有另一种方法lazy
可以组合来修改枚举数。
a_very_long_array.map.lazy
如果map
总是占用一个块,则必须有另一个方法,如map_lazy
,类似地,其他迭代器也可以做同样的事情。
答案 4 :(得分:0)
Enumerator允许内部和外部迭代的类
=> array = [1,2,3,4,5]
=> array.map
=> #<Enumerator: [2, 4, 6, 8, 10]:map>
=> array.map.next
=> 2
=> array.map.next_values
=> [0] 2
答案 5 :(得分:0)
我猜有时你想将Enumerator
传递给另一个方法,不管这个Enumerator
来自哪个地方:map
,slice
,无论如何:
def report enum
if Enumerator === enum
enum.each { |e| puts "Element: #{e}" }
else
raise "report method requires enumerator as parameter"
end
end
> report %w[one two three].map
# Element: one
# Element: two
# Element: three
> report (1..10).each_slice(2)
# Element: [1, 2]
# Element: [3, 4]
# Element: [5, 6]
# Element: [7, 8]
# Element: [9, 10]