Ruby中的“地图”方法有什么作用?


250

我是编程新手。有人可以解释一下该怎么.map做:

params = (0...param_count).map

9
一次问一个问题。map是在Enumerable对象上发现的常见“功能”方法,用于转换序列中的值(有特殊考虑)。.....创建范围的方法。另外,熟悉 REPL,您可以在这里自己尝试一下!:)

5
红宝石的REPL是irb,对于Rails来说是rails c。REPL允许您直接针对语言外壳本身测试代码。
加里

Answers:


431

map方法接受一个可枚举的对象和一个块,并为每个元素运行该块,并从该块输出每个返回的值(除非使用map!)

[1, 2, 3].map { |n| n * n } #=> [1, 4, 9]

ArrayRange是可枚举的类型。map与一个块一起返回一个数组。 map!改变原始数组。

这哪里是有帮助的,是什么样的区别map!each?这是一个例子:

names = ['danil', 'edmund']

# here we map one array to another, convert each element by some rule
names.map! {|name| name.capitalize } # now names contains ['Danil', 'Edmund']

names.each { |name| puts name + ' is a programmer' } # here we just do something with each element

输出:

Danil is a programmer
Edmund is a programmer

3
谢谢speransky的例子。那么.map与.each有何不同?
bigpotato 2012年

2
啊,我明白了。因此,.map实际上会改变数组,而.each只是循环遍历该数组以访问值,同时保持原始数组不变?
bigpotato 2012年

24
这是危险的休闲读者,开头一句描述map,就好像是map!
kaleidic

12
要查看地图和每个地图之间的区别,请打开一个IRB窗口,并在以下代码中查看y和z的结果:y = [1,2,3] .each {| x | x + 1}; z = [1,2,3] .map {| x | x + 1}
davej

7
@Inquisitive:提供块时,“每个”返回调用它的数组(在示例中为[1,2,3]),“映射”返回一个新数组,其中填充了由该块计算出的值。这可能会有所帮助:设置变量ary = [1,2,3],然后检查它是object_id。然后运行y = ary.each {| x | x + 1}; z = ary.map {| x | x + 1}。现在检查y和z的object_id。y与ary具有相同的object_id(因为每个返回的ary),但z具有不同的object_id,因为map返回了一个新数组。
davej 2014年

66

map以及selecteach是我代码中Ruby的主要工作之一。

它允许您对每个数组对象运行操作,并将它们全部返回到同一位置。一个示例是将数字数组加1:

[1,2,3].map {|x| x + 1 }
#=> [2,3,4]

如果您可以对数组的元素运行单个方法,则可以采用简写形式,例如:

  1. 要在上面的示例中执行此操作,您必须执行以下操作

    class Numeric
      def plusone
        self + 1
      end
    end
    [1,2,3].map(&:plusone)
    #=> [2,3,4]
  2. 为了更简单地使用&快捷方式,我们使用另一个示例:

    ["vanessa", "david", "thomas"].map(&:upcase)
    #=> ["VANESSA", "DAVID", "THOMAS"]

在Ruby中转换数据通常涉及一系列map操作。研究mapselect,它们是主库中一些最有用的Ruby方法。它们和一样重要each

map也是的别名collect。请在概念上使用最适合您的方法。)

更多有用的信息:

如果您正在运行或运行的Enumerable对象包含一组Enumerable元素(哈希,数组),则可以在块管道中声明每个这些元素,如下所示:eachmap

[["audi", "black", 2008], ["bmw", "red", 2014]].each do |make, color, year|
  puts "make: #{make}, color: #{color}, year: #{year}"
end
# Output:
# make: audi, color: black, year: 2008
# make: bmw, color: red, year: 2014

对于哈希(也是一个Enumerable对象),哈希只是一个元组数组,其中包含用于解释程序的特殊指令。第一个“管道参数”是关键,第二个是值。

{:make => "audi", :color => "black", :year => 2008}.each do |k,v|
    puts "#{k} is #{v}"
end
#make is audi
#color is black
#year is 2008

要回答实际问题:

假定这params是一个哈希,这将是映射它的最佳方法:使用两个块参数而不是一个参数来捕获哈希中每个解释的元组的键和值对。

params = {"one" => 1, "two" => 2, "three" => 3}
params.each do |k,v|
  puts "#{k}=#{v}"
end
# one=1
# two=2
# three=3

在irb中,这对我不起作用。我进入NoMethodError: private method 'plusone' called for 1:FixnumRuby 2,在Ruby 1.9 / 1.8中获得“错误的args数量”。无论如何,我使用了lambda:plusone = ->(x) { x + 1 }然后取出了符号说明符:[1,2,3].map(&plusone)
tjmcewan 2014年

1
嗯,听起来就像您private在放置方法之前在类中声明的那样
boulder_ruby 2014年

是的,完全可以。除了不是。:(首先,它是在没有类的纯脚本中,其次是在纯irb中。这是我的代码复制/粘贴:gist.github.com/tjmcewan/a7e4feb2976a93a5eef9
tjmcewan14年

是的,对不起,我完全在我的代码中放了一个不好的例子。尝试修改后的代码。现在可以使用...
boulder_ruby 2014年

1
@boulder_ruby是否可以使用普通方法来执行此操作-如不是类方法?
tekknolagi 2014年

6

使用ruby 2.4,您可以使用进行相同的操作transform_values,此功能是从rails提取到ruby的。

h = {a: 1, b: 2, c: 3}

h.transform_values { |v| v * 10 }
 #=> {a: 10, b: 20, c: 30}


3

它将功能“映射”到Enumerable一个范围内的每个项目(在本例中为范围)。因此,它将调用从0到的每个整数传递一次的块param_count(不包括-您对点是正确的),并返回包含每个返回值的数组。

这是的文档Enumerable#map它还有一个别名collect


这很奇怪,但Range#map实际上将其转换为数组。
Pedro Nascimento 2012年

1
@PedroNascimento:是的,那是我说的?
Ry-

抱歉,我不知道本身调用的map没有Enumerable像每个一样返回。我以为是。
Pedro Nascimento 2012年

2

Map是可枚举模块的一部分。与“收集”非常相似,例如:

  Class Car

    attr_accessor :name, :model, :year

    Def initialize (make, model, year)
      @make, @model, @year = make, model, year
    end

  end

  list = []
  list << Car.new("Honda", "Accord", 2016)
  list << Car.new("Toyota", "Camry", 2015)
  list << Car.new("Nissan", "Altima", 2014)

  p list.map {|p| p.model}

Map提供了由块参数返回的遍历数组的值。


映射与收集完全相同。
BKSpurgeon '16

0

#each

#each为数组中的每个元素运行一个函数。以下两个代码摘录是等效的:

x = 10
["zero", "one", "two"].each{|element|
    x++
    puts element
}
x = 10
array = ["zero", "one", "two"]

for i in 0..2
    x++
    puts array[i]
end

#map

#map将函数应用于数组的每个元素,返回结果数组。以下是等效的:

array = ["zero", "one", "two"]
newArray = array.map{|element| element.capitalize()}
array = ["zero", "one", "two"]

newArray = []
array.each{|element|
    newArray << element.capitalize()
}

#map!

#map!就像#map,但是在适当的地方修改数组。以下是等效的:

array = ["zero", "one", "two"]
array.map!{|element| element.capitalize()}
array = ["zero", "one", "two"]
array = array.map{|element| element.capitalize()}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.