【问题标题】:What is the use of map method in ruby? [duplicate]ruby中map方法有什么用? [复制]
【发布时间】:2013-09-10 23:04:15
【问题描述】:

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

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

上面将打印 caps 中的值。

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

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

【问题讨论】:

  • 您是否尝试过阅读有关这些方法的文档?例如:Enumerable#map.
  • 这是一个ruby 的问题,所以我更改了标签和标题。
  • @SergioTulentsev:抱歉,我对 ruby​​ 和 rails 很陌生,文档对我来说不是很清楚......
  • 只是好奇 - 您正在阅读哪些不清楚的文档?
  • map 的情况下,它将执行块中的内容并执行puts,就像each 一样,但它也会收集您的puts 语句的返回值放入一个数组并作为结果返回。该结果对您毫无用处,因此在这种情况下使用 map 毫无意义。您将获得nils 的数组。 each 执行块内的内容而不收集任何结果。

标签: ruby


【解决方案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,以便您以后可以使用新值。

顺便说一句,作为一种快捷方式,如果您将 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 }会更清晰更简单。

【讨论】:

  • 非常感谢,就在最后一行 a.map(&:upcase) 而不是 a.map(:upcase)... 还有最后一个问题... 每个返回逗号分隔值和map 和 collect 返回一个数组。
  • 我想你的意思可能是这样的:a.map(&:upcase).select { |n| n.size.even? } .each(&Kernel.method(:puts)) 最后一个例子。
  • @NickVeys 你说得对,我搞砸了selectputs。至于&:upcase:upcase,我认为map 在更高版本的Ruby 中也可以使用符号,但似乎不是。也许这只是一个 Rails ActiveSupport 扩展。我也解决了这个问题。
  • @Kevin 至于你的最后一个问题,当你调用 Array 上的方法时,mapcollect (它们是同一方法的不同名称)返回新的,更改的Array。但是,each 不返回“逗号分隔值”——它只返回原始的、未更改的 Array(通常在值之间用逗号显示 )。所以这三个方法都返回Arrays——一些新的,一些旧的。
  • @Kevin 答案已更新。
【解决方案2】:

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 的输出,你会得到一个 nil 数组:

 > a2 = a.collect { |i| puts i.upcase }
=> [nil, nil, nil]

【讨论】:

  • 您应该将其与each 进行比较以显示差异。 OP 似乎混淆了两者。
【解决方案3】:

map 的情况下,它将执行块中的内容并执行puts 就像each 所做的那样,但它还将您的puts 语句的返回值收集到一个数组中并将其返回为结果。该结果对您毫无用处,因此在这种情况下使用 map 毫无意义。您将获得nils 的数组。 each 执行块内的内容而不收集任何结果。

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']

【讨论】:

  • 非常感谢您对 mbratch 的回答...谢谢
【解决方案4】:
  • 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"]
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 2016-12-19
    • 2012-12-26
    • 2011-12-04
    • 2013-06-02
    • 2016-11-08
    • 2011-05-03
    相关资源
    最近更新 更多