我一直在谷歌搜索并没有得到该map
方法的真正用法。这是我在控制台中尝试过的。
a = ["kevin","john","ryan"]
a.each {|i| puts i.upcase}
以上将打印caps中的值。
a = ["kevin","john","ryan"]
a.map {|i| puts i.upcase}
这也将打印caps中的值。那么 map 方法有什么特别之处呢?并且任何人都可以引导我找到这个主题的一个很好的来源,以便更好地理解。
我一直在谷歌搜索并没有得到该map
方法的真正用法。这是我在控制台中尝试过的。
a = ["kevin","john","ryan"]
a.each {|i| puts i.upcase}
以上将打印caps中的值。
a = ["kevin","john","ryan"]
a.map {|i| puts i.upcase}
这也将打印caps中的值。那么 map 方法有什么特别之处呢?并且任何人都可以引导我找到这个主题的一个很好的来源,以便更好地理解。
在您的示例中,当您想立即单独打印每个值时,each
效果会更好。map
当您想将新版本的元素保存回数组中并稍后在程序中使用该数据时,这很有用。
例如,假设您想忘记名称曾经是小写还是大写。在您的程序中的任何地方,名称都是大写的,所以您现在只想将它们转换为大写并完成。
a = ["kevin","john","ryan"]
a = a.map{ |n| n.upcase }
将其与 using 进行比较each
-each_with_index
实际上,您必须使用 ,因为您需要一种方法来分配新值:
a = ["kevin","john","ryan"]
a.each_with_index do |n, i|
a[i] = n.upcase
end
这是适合这种情况map
的。获取Enumerable
具有更改值的新值,以便您以后可以使用新值。
顺便说一句,作为一种快捷方式,如果您将map
ped 变量分配回自身,而不是a = a.map{}
,您可以使用a.map!{}
.
另一种情况是,如果您想打印具有偶数个字母的所有名称。如果您使用each
,它的外观如下:
a = ["kevin","john","ryan"]
a.each do |n|
if n.size.even?
puts n.upcase
end
end
如果你使用map
,那会给你一个数组。然后您可以将该数组传递给select
,最后用于each
打印值。这对于阅读代码的任何人来说都更清楚地分离了这些步骤,并且如果您想稍后扩展它,可以使您的代码更加模块化。
a = ["kevin","john","ryan"]
a.map(&:upcase) \
.select{ |n| n.size.even? } \
.each{ |n| puts n }
最后一行也可能是这样的:
.each(&Kernel.method(:puts))
但这对于这么少的代码来说可能是不必要的混乱。这样做是使用运算符将全局puts
方法转换为块&
。Kernel
包含所有全局方法,并且.method
是您使用类中的方法获取变量的方式。所以.each(&Kernel.method(:puts))
说“获取全局puts
方法,并将其转换为一个块,以便puts
以块参数作为参数调用它”。但在这种情况下,写起来更清晰、更简单.each{ |n| puts n }
。
map
(或collect
)将块的输出收集到一个数组中。
你的例子没那么有用;该块仅用于其副作用。
与a.map { |i| i.upcase }
or,更 Ruby-y,比较a.collect(&:upcase)
:
> a2 = a.collect(&:upcase)
=> ['KEVIN', 'JOHN', 'RYAN']
each
简单地返回它被调用的值,在这种情况下,原始数组。
没有puts
显示的输出:
> a2 = a.each(&:upcase)
=> ['kevin', 'john', 'ryan']
如果你收集你的输出,puts
你会得到一个 nil 数组:
> a2 = a.collect { |i| puts i.upcase }
=> [nil, nil, nil]
无论打印什么都是评估块puts
的副作用。关于评估块的副作用,each
并且map
是相同的。
除了副作用(某些方法没有)之外,所有 Ruby 方法都有一个返回值。each
和之间不同的是返回值map
。前者返回接收者,后者返回块的评估结果。
b = a.each{|i| puts i.upcase}
b # => ["kevin","john","ryan"]
b = a.map{|i| puts i.upcase}
b # => ["KEVIN","JOHN","RYAN"]
在 的情况下map
,它将执行块中的内容并执行与执行相同的puts
操作each
,但它还将您的 puts 语句的返回值收集到一个数组中并将其作为结果返回。该结果对您毫无用处,因此在这种情况下使用 map 毫无意义。你会得到一个s数组nil
。每个执行块内的内容而不收集任何结果。
each
执行块并返回原始数组:
> a = ["kevin","john","ryan"]
=> ["kevin", "john", "ryan"]
> a.each {|i| puts i.upcase}
KEVIN
JOHN
RYAN
=> ["kevin", "john", "ryan"]
>
map
执行块并以数组的形式返回块中的值:
> a = ["kevin","john","ryan"]
=> ["kevin", "john", "ryan"]
> a.map {|i| puts i.upcase}
KEVIN
JOHN
RYAN
=> [nil, nil, nil]
>
注意返回的数组nil
,因为每个都puts
返回了 anil
并map
收集了那些。如果你想在一个数组中收集大写字符串,你可以map
像这样正确使用:
> a.map {|i| i.upcase}
=> ['KEVIN', 'JOHN', 'RYAN']
或者,等价地,a.map(&:upcase)
。您还可以将其分配给变量:
> foo = a.map {|i| i.upcase}
=> ['KEVIN', 'JOHN', 'RYAN']
> foo
=> ['KEVIN', 'JOHN', 'RYAN']