🚀

[eature #21386] #map と #join を同時に行う Enumerable#join_map を追加する提案

に公開
2

[eature #21386] Introduce Enumerable#join_map

  • #map#join を同時に行う Enumerable#join_map を追加する提案
  • users.map { _1.name }.join(", ")users.join_map(", ") { _1.name } に置き換えるようなイメージ
  • モチベーションとしては map {}.join だと2回イテレーションしたり中間オブジェクトが生成されたりするのでそれを回避したいというところ
  • いわゆる #filter_map の亜種としてほしいみたい
  • 実装イメージは以下のような感じ
module Enumerable
  def join_map(sep = "")
    return "" unless block_given?

    str = +""
    first = true

    each do |item|
      str << sep unless first
      str << yield(item).to_s
      first = false
    end

    str
  end
end
  • Elixir だと似たような map_join という関数があるらしいですね、へえ
  • これなんですが現時点だと #join#map を組み合わせただけなので Reject されている
  • https://bugs.ruby-lang.org/issues/21386#note-9
  • これ系は組み合わせが無限にあるのでもし導入したいのであればパフォーマンスや有用性などの『それなりの効果』を提示できないと説得するのはむずかしそうですねえ
  • https://bugs.ruby-lang.org/issues/21386#note-7
  • ちなみに #filter_map はよく #map + #compact の組み合わせと思われているが厳密に言うと挙動が異なる
    • 例えば以下のようなコードだと結果が違う
ary = [1, 2, 3, 4, 5]

#
pp ary.map { _1.even? }.compact
# => [false, true, false, true, false]

pp ary.filter_map { _1.even? }
# => [true, true]
  • これは #compact が『 nil の要素のみ取り除く』に対して #filter_map は『偽の要素を取り除く』という挙動になっているからですね
  • なので #compactfalse は取り除かれない
# nil は取り除くが false はそのまま
pp [1, 2, nil, false, 3].compact
# => [1, 2, false, 3]
  • なので厳密に言うと #filter_map はその名前の通り #map + #filter と同じ挙動になる
ary = [1, 2, 3, 4, 5]

pp ary.map { _1.even? }.compact
# => [false, true, false, true, false]

pp ary.filter_map { _1.even? }
# => [true, true]

pp ary.map { _1.even? }.filter { _1 }
# => [true, true]
GitHubで編集を提案

Discussion

noobooleannooboolean

記事拝見させていただきました!
ありがとうございます。

気になったのでコメント失礼します。
タイトルと本文1箇所が job_map になっていますが、 正しくは join_map かなと思いました

ご確認よろしくお願いします!