在Ruby中,技术上是什么 - array.reject或array.select没有块呢?

时间:2016-03-31 16:28:45

标签: arrays ruby enumerator

据我所知,array.rejectarray.select什么都不做:

[nil, false, true].reject  # Should have been reject.to_a for this example.
 => [nil, false, true] 
[nil, false, true].select  # Should have been select.to_a for this example.
 => [nil, false, true] 

对于我尝试编写的代码,compact是我所需要的,但我很好奇为什么rejectselect没有阻止什么都没做 - 我期待着{ |e| e }的默认阻止,rejectcompact,“选择”将是一些奇怪的反紧凑。

默认阻止做什么?

编辑:对不起,我错过了上面表达式末尾的'.to_a',我希望这会触发某种懒惰的评估,并使拒绝/选择枚举做一些有用的事情。我通常剪切和粘贴我的例子来避免这种情况。

2 个答案:

答案 0 :(得分:2)

生成Enumerator

en = [1,2,3].reject
# => #<Enumerator: [1, 2, 3]:reject>
en.each{|n| n == 1}
# => [2, 3]

答案 1 :(得分:2)

对于许多Ruby方法,块是可选的。当没有给出块时,通常返回枚举器。至少有几个原因你可能想要一个普查员。

#1将枚举数与类Enumerator中的方法一起使用。

这是一个例子。假设您希望在字符串中替换字母大小写。一种传统方式是:

"oh happy day".each_char.with_index.map { |c,i| i.odd? ? c.upcase : c.downcase }.join
  #=> "oH HaPpY DaY" 

但你可以写一下:

enum = [:odd, :even].cycle
"oh happy day".each_char.map { |c| enum.next==:odd ? c.upcase : c.downcase }.join

或者

enum = [:upcase, :downcase].cycle
"oh happy day".each_char.map { |c| c.send(enum.next) }.join

请参阅Array#cycleEnumerator#next的文档。

#2使用枚举器链接方法

在我上面的第一个例子中,我写道:

"oh happy day".each_char.with_index.map...

如果您检查String#each_charEnumerator#with_index的文档,您会发现这两种方法都可以在有或没有块的情况下使用。在这里他们都使用没有块。这使得三种方法可以链接

研究以下的返回值。

enum0 = "oh happy day".each_char
  #=> #<Enumerator: "oh happy day":each_char> 
enum1 = enum0.with_index
  #=> #<Enumerator: #<Enumerator: "oh happy day":each_char>:with_index> 
enum2 = enum1.map
  #=> #<Enumerator: #<Enumerator: #<Enumerator:
  #     "oh happy day":each_char>:with_index>:map> 

您可能希望将enum1enum2视为“复合”枚举数。

您显示的返回值为:

[nil, false, true].reject

是:

#=> [nil, false, true]

但这不正确。返回值为:

#<Enumerator: [nil, false, true]:reject>

如果我们写:

enum = [nil, false, true].reject

然后:

enum.each { |e| e }
  #=> [nil, false] 

(从Ruby v2.3开始,我们可以编写enum.reject(&:itself))。这使用方法Enumerator#each,导致enum调用Array#each,因为reject的接收者是类Array的实例。