我一直在使用Google搜索而没有真正使用map
方法。这是我在控制台中尝试的内容。
a = ["kevin","john","ryan"]
a.each {|i| puts i.upcase}
以上内容会打印大写中的值。
a = ["kevin","john","ryan"]
a.map {|i| puts i.upcase}
这也会打印大写中的值。那么map方法有什么特别之处呢?任何人都可以引导我找到这个主题的良好来源,以便更好地理解。
答案 0 :(得分:1)
map
(或collect
)收集数组中块的输出。
你的例子没那么有用;该块仅用于其副作用。
与a.map { |i| i.upcase }
或更多Ruby-y,a.collect(&:upcase)
:
> a2 = a.collect(&:upcase)
=> ['KEVIN', 'JOHN', 'RYAN']
each
只返回调用它的值,在本例中是原始数组。
未显示puts
的输出:
> a2 = a.each(&:upcase)
=> ['kevin', 'john', 'ryan']
如果你收集puts
的输出,你会得到一系列nils:
> a2 = a.collect { |i| puts i.upcase }
=> [nil, nil, nil]
答案 1 :(得分:1)
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"]
答案 2 :(得分:1)
在map
的情况下,它将执行块中的内容并像puts
那样执行each
,但它也会将puts语句的返回值收集到一个数组并返回结果。这个结果对你没用,所以在这种情况下使用map是没有意义的。你会得到一组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
都返回了nil
和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']
答案 3 :(得分:1)
在您的示例中,当您想要立即单独打印每个值时,each
会更好。当您想要将新版本的元素保存回数组并在程序中稍后使用该数据时,map
非常有用。
例如,假设你想忘记名字是低级还是大写。在程序的任何地方,名称都是大写的,所以你只想将它们转换为大写,然后用它完成。
a = ["kevin","john","ryan"]
a = a.map{ |n| n.upcase }
将其与使用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 }
更清晰,更简单。