🚀
[eature #21386] #map と #join を同時に行う Enumerable#join_map を追加する提案
[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は『偽の要素を取り除く』という挙動になっているからですね - なので
#compactはfalseは取り除かれない
# 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]
Discussion
記事拝見させていただきました!
ありがとうございます。
気になったのでコメント失礼します。
タイトルと本文1箇所が
job_mapになっていますが、 正しくはjoin_mapかなと思いましたご確認よろしくお願いします!
ありがとうございます。修正しました。