在 Ruby 中,从技术上讲,没有块的 array.reject 或 array.select 有什么作用?
In Ruby, what - technically - does array.reject or array.select without a block do?
据我所知,array.reject
和 array.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
是我所需要的,但我很好奇为什么没有块的 reject
和 select
什么都不做 - 我是期望默认块 { |e| e }
所以 reject
将是 compact
而 'select' 将是一些奇怪的反紧凑。
默认块在做什么?
编辑:抱歉,我漏掉了上面表达式末尾的“.to_a”,我希望这会触发某种惰性求值并使 reject/select 枚举执行有用的东西。我通常剪切和粘贴我的例子以避免这种事情。
对其进行 Enumerator
:
en = [1,2,3].reject
# => #<Enumerator: [1, 2, 3]:reject>
en.each{|n| n == 1}
# => [2, 3]
块对于许多 Ruby 方法是可选的。当没有给出块时,枚举器通常是 returned。您可能需要枚举器至少有几个原因。
#1 将枚举器与 class 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#cycle and Enumerator#next 的文档。
#2 使用枚举器链接方法
在我上面的第一个例子中,我写道:
"oh happy day".each_char.with_index.map...
如果您查看 String#each_char and Enumerator#with_index 的文档,您会发现这两种方法都可以使用或不使用块。在这里,它们都在没有块的情况下使用。这使得这三个方法可以 链接 .
研究以下 return 值。
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>
您可能希望将 enum1
和 enum2
视为 "compound" 枚举数。
您显示的 return 值:
[nil, false, true].reject
成为:
#=> [nil, false, true]
但这是不正确的。 return 值为:
#<Enumerator: [nil, false, true]:reject>
如果我们写:
enum = [nil, false, true].reject
然后:
enum.each { |e| e }
#=> [nil, false]
(从 Ruby v2.3 开始,我们可以写成 enum.reject(&:itself)
)。这使用方法 Enumerator#each, causing enum
to invoke Array#each 因为 reject
的接收者是 class Array
的一个实例。
据我所知,array.reject
和 array.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
是我所需要的,但我很好奇为什么没有块的 reject
和 select
什么都不做 - 我是期望默认块 { |e| e }
所以 reject
将是 compact
而 'select' 将是一些奇怪的反紧凑。
默认块在做什么?
编辑:抱歉,我漏掉了上面表达式末尾的“.to_a”,我希望这会触发某种惰性求值并使 reject/select 枚举执行有用的东西。我通常剪切和粘贴我的例子以避免这种事情。
对其进行 Enumerator
:
en = [1,2,3].reject
# => #<Enumerator: [1, 2, 3]:reject>
en.each{|n| n == 1}
# => [2, 3]
块对于许多 Ruby 方法是可选的。当没有给出块时,枚举器通常是 returned。您可能需要枚举器至少有几个原因。
#1 将枚举器与 class 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#cycle and Enumerator#next 的文档。
#2 使用枚举器链接方法
在我上面的第一个例子中,我写道:
"oh happy day".each_char.with_index.map...
如果您查看 String#each_char and Enumerator#with_index 的文档,您会发现这两种方法都可以使用或不使用块。在这里,它们都在没有块的情况下使用。这使得这三个方法可以 链接 .
研究以下 return 值。
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>
您可能希望将 enum1
和 enum2
视为 "compound" 枚举数。
您显示的 return 值:
[nil, false, true].reject
成为:
#=> [nil, false, true]
但这是不正确的。 return 值为:
#<Enumerator: [nil, false, true]:reject>
如果我们写:
enum = [nil, false, true].reject
然后:
enum.each { |e| e }
#=> [nil, false]
(从 Ruby v2.3 开始,我们可以写成 enum.reject(&:itself)
)。这使用方法 Enumerator#each, causing enum
to invoke Array#each 因为 reject
的接收者是 class Array
的一个实例。