-1

我一直在谷歌搜索并没有得到该map方法的真正用法。这是我在控制台中尝试过的。

a = ["kevin","john","ryan"]
a.each {|i| puts i.upcase}

以上将打印caps中的值。

a = ["kevin","john","ryan"]
a.map {|i| puts i.upcase}

这也将打印caps中的值。那么 map 方法有什么特别之处呢?并且任何人都可以引导我找到这个主题的一个很好的来源,以便更好地理解。

4

4 回答 4

1

在您的示例中,当您想立即单独打印每个值时,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具有更改值的新值,以便您以后可以使用新值。

顺便说一句,作为一种快捷方式,如果您将mapped 变量分配回自身,而不是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 }

于 2013-09-06T19:17:46.823 回答
1

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]
于 2013-09-06T19:05:53.717 回答
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"]
    
于 2013-09-06T19:10:31.143 回答
1

在 的情况下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返回了 anilmap收集了那些。如果你想在一个数组中收集大写字符串,你可以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']
于 2013-09-06T19:10:38.520 回答