flat_mapとは?
配列に対して利用できるメソッドで、flatten
メソッドと、map
メソッドを合わせたようなメソッド。
flatten
ネストした配列を平坦化(へいたんか)してくれるメソッド
[['a', 1], ['b', 2], ['c', 3]].flatten
# => ["a", 1, "b", 2, "c", 3]
[1, [2, [3, 4]], 5].flatten
# ネストの深さに関わらず、1次元の配列に変換される
# => [1, 2, 3, 4, 5]
map
配列の各要素に対して処理を行い、その結果を新しい配列として返すメソッド。元の配列は変更されない。
numbers = [1, 2, 3, 4, 5]
numbers.map { |n| n * n }
# => [1, 4, 9, 16, 25]
flat_mapを実際利用した場面
- とある店舗の営業が11時~14時
- 注文を受け付ける時間の区切りを15分ごとに設定したい
と言う時に、以前は
shop_hours = [11, 12, 13]
shop_hours.map do |h|
0.step(45, 15).map do |m|
"#{format "%02d", h}:#{format "%02d", m}"
end
end.flatten
# => ["11:00", "11:15", "11:30", "11:45", "12:00", "12:15", "12:30", "12:45", "13:00", "13:15", "13:30", "13:45"]
と書いていた。
しかしflat_map
を用いて
hours.flat_map do |h|
0.step(45, 15).map do |m|
"#{format "%02d", h}:#{format "%02d", m}"
end
end
と書くことができた。
注意点
flat_map
の振る舞いは
元の配列の各要素に対して
「flattenで平坦化されてからmapが実行される」のではなく
「mapで各要素に対して処理が行われた後、flattenで平坦化される」ということに注意が必要。例えば「ネストされた配列から数値のみを抽出したい」とした場合
array = [['a', 1], ['b', 2], ['c', 3]]
# 平坦化された後の配列に対して数値のみを抽出することを期待している
array.flat_map{ |data| data.is_a?(Integer) }
# ['a', 1].is_a?(Integer)等になりfalseとなる
# => [false, false, false]
と言うやり方はできない。やるのであれば、
array = [['a', 1], ['b', 2], ['c', 3]]
# ネストされた配列の中を数値のみとしその後平坦化する
array.flat_map{ |data| data.grep(Integer) }
# => [1, 2, 3]
のように書く。