Project

General

Profile

Actions

Feature #15024

open

Support block in Array#join

Added by graywolf (Gray Wolf) over 5 years ago. Updated over 5 years ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:88635]

Description

I think it could be handy to have block support in Array#join.

For example

> puts %w{a b c d}.join { |_, _, i| i % 2 == 1 ? "\n" : ', ' }
a, b
c, d

not sure what arguments exactly the block should take, atm I'm thinking
of

> %w{a b c d}.join { |before, after, i| puts "#{before}:#{after}:#{i}" }
a:b:0
b:c:1
c:d:2

Would appreciate some feedback before I try putting together patch for this.


Related issues 1 (0 open1 closed)

Related to Ruby master - Feature #14022: String#surroundRejectedActions

Updated by jeremyevans0 (Jeremy Evans) over 5 years ago

Your examples are both possible to implement using existing Array methods:

puts %w{a b c d}.each_slice(2).map{|a| a.join(", ")}.join("\n")
a, b
c, d

%w{a b c d}.each_cons(2).with_index.each{|a, i| puts (a << i).join(":")}
a:b:0
b:c:1
c:d:2

In the first case, your example has the block return the join separator. In the second example you don't appear to be returning the separator, you appear to be using the block for the side effect of iterating over the equivalent of each_cons(2).with_index (with before and after as separate block arguments).

I don't think adding block support to Array#join improves either example, and I think it makes the code more difficult to understand.

Updated by graywolf (Gray Wolf) over 5 years ago

Doesn't #each_slice create temporary array for each pair? Doesn't seem very efficient. But assuming that does not matter, can I use something similar to produce %{a b c d}.join { |_,_,i| i.to_s } == "a0b1c2d", is there oneliner for this too?

The second example was just illustrating what would be passed into the block.

I still think having possibility of block returning the separate is nice thing.

Updated by jeremyevans0 (Jeremy Evans) over 5 years ago

For %{a b c d}.join { |_,_,i| i.to_s } == "a0b1c2d", you could do:

*a, l = %w{a b c d}; a.each.with_object('').with_index{|(v, str), i| str << v << i.to_s} << l

That definitely isn't as nice looking. I can see the benefit of having the block return the separator, but I'm not sure how common such a need is. It's fairly straightforward to build the string manually in the cases you would need a separate separator per pair of items.

Could you share a practical example that would benefit from Array#join block support?

Updated by nobu (Nobuyoshi Nakada) over 5 years ago

Array#join concatenates array elements recursively.
What do you expect as the index between different level elements?

Updated by mame (Yusuke Endoh) over 5 years ago

I'd like somewhat to agree with the motivation. Indeed, I sometimes feel I want to insert separators between each pair of elements. However, I cannot remember the concrete situation, and how often I have encountered the situation. The motivation examples in this ticket look too artificial, so not convincing to me. Could you show us a more real-world use case?

Personally, I don't think it is a good idea to extend Array#join. It is specialized to generation of a string, but I'm unsure if it is enough. And, the block parameters |before, after, index| look too ad-hoc to me. Passing an index is a role of each_with_index. It is not a responsibility of join, I think.

Actions #6

Updated by duerst (Martin Dürst) over 5 years ago

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0