ruby中map方法的用途是什么?

时间:2013-09-06 18:56:01

标签: ruby

我一直在使用Google搜索而没有真正使用map方法。这是我在控制台中尝试的内容。

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

以上内容会打印大写中的值。

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

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

4 个答案:

答案 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打印的是评估块的副作用。关于评估阻止的副作用,eachmap是相同的。

  • 除了副作用(某些方法没有),所有Ruby方法都有返回值。它是eachmap之间不同的返回值。前者返回接收者,后者返回块的评估结果。

    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都返回了nilmap收集的数据。如果你想收集数组中的大写字符串,你可以像这样使用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 }更清晰,更简单。