Rubyの「マップ」メソッドは何をしますか?


250

プログラミングは初めてです。誰かが何を.mapするのか説明できますか:

params = (0...param_count).map

9
掲載し1時間に質問を。mapシーケンスの値を変換するために使用されるEnumerableオブジェクトにある一般的な「関数型」メソッドです(特別な考慮事項があります)。.....範囲を作成する方法です。また、REPLについても理解してください。REPLを自分で試すことができます。:)

5
RubyのREPLはirb、Railsの場合はrails cです。REPLを使用すると、言語シェル自体に対してコードを直接テストできます。
ゲイリー

回答:


431

このmapメソッドは、列挙可能なオブジェクトとブロックを取り、要素ごとにブロックを実行し、ブロックから返された各値を出力します(元のオブジェクトは、以下を使用しない限り変更されません)map!)

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

Arrayそして、Range列挙型です。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!
カレイディック

12
mapとeachの違いを確認するには、IRBウィンドウを開き、次のコードでyとzの結果を確認します。y= [1,2,3] .each {| x | x + 1}; z = [1,2,3] .map {| x | x + 1}
davej 2013年

7
@Inquisitive: 'each'は、ブロックが指定されたときにそれを呼び出す配列(例では[1,2,3])を返し、 'map'はブロックによって計算された値が入力された新しい配列を返します。これは役立つかもしれません:変数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のため)が、mapが新しい配列を返したため、zは異なるobject_idを持っています。
davej 14

66

mapselectおよびeach私のコードで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ます。概念的には、自分に最も適したものを使用してください。)

より役立つ情報:

場合列挙あなたが実行しているオブジェクトeachまたはmap上では、列挙要素(ハッシュ、配列)のセットが含まれている、あなたはそうのようなあなたのブロックパイプ内のこれらの要素のそれぞれを宣言することができます。

[["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オブジェクトであり、ハッシュは、インタプリタ用の特別な指示を持つタプルの配列です)。最初の「パイプパラメータ」はキー、2番目は値です。

{: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がハッシュであると仮定すると、これはそれをマッピングする最善の方法です。1つではなく2つのブロックパラメーターを使用して、ハッシュ内の解釈された各タプルのキーと値のペアをキャプチャします。

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:Fixnumはruby 2 を取得し、ruby 1.9 / 1.8では「間違った数の引数」を取得しています。とにかく、私はラムダを使用しました:plusone = ->(x) { x + 1 }次にシンボル指定子を取り出します:[1,2,3].map(&plusone)
tjmcewan 2014年

1
privateメソッドを配置する前に、メソッドを配置するクラス内で宣言したように聞こえます
boulder_ruby '06 / 06/26

ええ、それは完全にあります。そうではなかった以外は。:(まず、それはクラスなしのストレートスクリプトで、2番目はプレーンirbでした。これが私のコードのコピー/貼り付けです。gist.github.com
tjmcewan

ええ、すみません、コードに悪い例を入れただけです。変更したコードを試してください。今すぐ機能します...
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}

4

0..param_count「param_countまで」を意味します。 0...param_count「param_countまで、ただし含まない」を意味します。

Range#mapは返されませんEnumerable。実際には配列にマッピングされます。と同じRange#to_aです。


3

関数を「Enumerableこの場合は範囲」の各項目に「マップ」します。したがって、0からparam_count(整数のみ-ドットについては正しい)の整数ごとに1回渡されたブロックを呼び出し、各戻り値を含む配列を返します。

これはのドキュメントですEnumerable#mapまた、エイリアスもありcollectます。


奇妙ですが、Range#map実際には配列に変換します。
Pedro Nascimento 2012

1
@PedroNascimento:ええ...それは私が言ったことですか?
Ry-

申し訳ありませんが、それ自体で呼び出されたマップがEnumerable、それぞれのようなを返さないことを知りませんでした。そうだと思った。
Pedro Nascimento 2012

2

Mapは列挙可能なモジュールの一部です。"collect"に非常に似ています。例:

  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はcollectとまったく同じです。
BKSpurgeon

0

#each

#each配列内の各要素に対して関数を実行します。次の2つのコードの抜粋は同等です。

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()}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.