rubyのflat_mapをちゃんと理解した
2019年の最初だし、ブログでも書いてみようという試み。
事の発端のツイート
コード読んでいて違和感あるけど、修正しなくても動いている場合のレビューが難しい。例えば、無駄なメソッド呼び出しとか。
— 神速 (@sinsoku_listy) 2018年12月31日
def foo(x)
a = x.flat_map(&:bar)
(a + [1]).flatten
end
この例は「flat_map使っているし、flatten要らないよね」って意図だったけど、@kamipoさんや@hanachin_さんからbarがネストした配列を返すときは必要というリプライを頂いた。
flat_mapよく分からなくなったので試した
実際に試してみて、flat_mapがmap+flatten(1)相当だと理解できた。
require 'rspec' RSpec.describe 'flat_map' do it 'mapしてflatten(1)と同じ' do nums = [1, 2, 3] # [num, [num*2, num**2]] になる配列 expected = [1, [2, 1], 2, [4, 4], 3, [6, 9]] x = nums.map { |n| [n, [n * 2, n**2]] }.flatten(1) expect(x).to eq expected y = nums.flat_map { |n| [n, [n * 2, n**2]] } expect(y).to eq expected z = nums.map { |n| [n, [n * 2, n**2]] }.flatten expect(z).to eq expected # Failure/Error: expect(z).to eq expected # # expected: [1, [2, 1], 2, [4, 4], 3, [6, 9]] # got: [1, 2, 1, 2, 4, 4, 3, 6, 9] end end RSpec::Core::Runner.invoke
まとめ
flat_map使っても、制限なしにflatになるわけではない。