* [ruby-core:122345] [Ruby Feature#21386] Introduce `Enumerable#join_map`
@ 2025-05-30 16:33 matheusrich (Matheus Richard) via ruby-core
0 siblings, 0 replies; only message in thread
From: matheusrich (Matheus Richard) via ruby-core @ 2025-05-30 16:33 UTC (permalink / raw)
To: ruby-core; +Cc: matheusrich (Matheus Richard)
Issue #21386 has been reported by matheusrich (Matheus Richard).
----------------------------------------
Feature #21386: Introduce `Enumerable#join_map`
https://bugs.ruby-lang.org/issues/21386
* Author: matheusrich (Matheus Richard)
* Status: Open
----------------------------------------
### 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/
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-05-30 16:34 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-30 16:33 [ruby-core:122345] [Ruby Feature#21386] Introduce `Enumerable#join_map` matheusrich (Matheus Richard) via ruby-core
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).