ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [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).