From: "Eregon (Benoit Daloze) via ruby-core" Date: 2025-07-15T20:12:40+00:00 Subject: [ruby-core:122785] [Ruby Feature#21386] Introduce `Enumerable#join_map` Issue #21386 has been updated by Eregon (Benoit Daloze). matz (Yukihiro Matsumoto) wrote in #note-9: > I hope JIT inlining will remove intermediate objects in the future. FWIW, that's not really feasible, at least for cases where the input array has variable size. Unless both Array#map and Array#join are intrinsified and handled as a compound operation of sort, but that's not really reasonable as Array#join is far from trivial. That said, I think the cost of the `map` is only a small fraction of the cost of the `join`, and so not worth having a new core method for this. ---------------------------------------- Feature #21386: Introduce `Enumerable#join_map` https://bugs.ruby-lang.org/issues/21386#change-114064 * Author: matheusrich (Matheus Richard) * Status: Rejected ---------------------------------------- ### Problem The pattern `.map { ... }.join(sep)` is extremely common in Ruby codebases: ```ruby users.map(&:name).join(", ") ``` It���s expressive but repetitive (both logically and computationally). This pattern allocates an intermediate array and does two passes over the collection. Real-world usage is widespread: - [Open source Ruby projects using this pattern](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F&type=code) - [Within Rails](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F+org%3Arails&type=code) - [Within Ruby itself](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F+org%3Aruby&type=code) ### Proposal Just like `filter_map` exists to collapse a common `map + compact`, this proposal introduces `Enumerable#join_map`, which maps and joins in a single pass. ```ruby users.join_map(", ", &:name) ``` A Ruby implementation could look like this: ```ruby 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 ``` The name `join_map` follows the precedent of `filter_map`, emphasizing the final operation (`join`) over the intermediate (`map`). ### Prior Art Some other languages have similar functionality, but with different names or implementations: #### Elixir Elixir has this via [the `Enum.map_join/3` function](https://hexdocs.pm/elixir/1.12/Enum.html#map_join/3): ```elixir Enum.map_join([1, 2, 3], &(&1 * 2)) "246" Enum.map_join([1, 2, 3], " = ", &(&1 * 2)) "2 = 4 = 6" ``` #### Crystal Crystal, on the other hand, [uses `Enumerable#join` with a block](https://crystal-lang.org/api/1.16.3/Enumerable.html#join%28separator%3D%22%22%2C%26%3AT-%3E%29-instance-method): ```crystal [1, 2, 3].join(", ") { |i| -i } # => "-1, -2, -3" ``` #### Kotlin Kotlin has a similar [function called `joinToString`](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html) that can take a transformation function: ```kotlin val chars = charArrayOf('a', 'b', 'c') println(chars.joinToString() { it.uppercaseChar().toString() }) // A, B, C ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/