17 Feb, 2011, Runter wrote in the 1st comment:
Votes: 0
In many languages a join operation for an array results in "spacers" being added. For example in ruby:

[1,2,3].join " "


That's going to return "1 2 3"

So my question is what's the best practice for implementing this functionality? There's some obvious but inelegant ways. For example you can iterate over a collection and concat the spacer on each pass except on the final pass. This usually requires an if statement and more importantly a way to know you're on the final pass of iteration. Another way is for n elements only iterating over n-1 elements. Then using a special case for the final element. This avoids using an if statement, but at best it seems dirty. These two examples:

10.times do |i|
print i;
print " " if i != 9 # all but final pass
end


9.times do |i|
print i;
print " ";
end
print 10;


Contrived examples, but if someone has something better please share. :p

edit: p.s. just looking for algorithm, doesn't need to be ruby specific.
17 Feb, 2011, kiasyn wrote in the 2nd comment:
Votes: 0
just do it aggressively then remove the last character at the end? :)
17 Feb, 2011, Runter wrote in the 3rd comment:
Votes: 0
kiasyn said:
just do it aggressively then remove the last character at the end? :)


That's one option, but my specific use case for joining isn't necessarily characters. There's no way for me to "remove" the last spacer in my specific case.
17 Feb, 2011, Tyche wrote in the 4th comment:
Votes: 0
Look at the implementation of the join function in ruby. It implements pretty much the same solution you came up with.
It calls ary_join_0, a loop over the elements concatenating separators and elements, except the last,
and then finally calls ary_join_1, adding in the final element without a separator.

How is ruby join() better? If it's buried in the implementation so you don't see how it works, is it more "elegant"
than if you had written it yourself?
18 Feb, 2011, Runter wrote in the 5th comment:
Votes: 0
Quote
How is ruby join() better? If it's buried in the implementation so you don't see how it works, is it more "elegant"
than if you had written it yourself?


I didn't say it was better. Fwiw different implementations of ruby I've looked at do it differently. So certainly it doesn't matter what the implementation under the hood is (and mileage probably varies depending on the specifics) for the end user. The point of this thread was to ask for a better solution than one I listed, not tell me if it's good enough for join implementation X it's good enough for me. Unless you're actually saying that's the best way to do it.
18 Feb, 2011, oenone wrote in the 6th comment:
Votes: 0
how i'd do it: print first value, and then append the rest with leading separator…

the opposite of your second example ;)
18 Feb, 2011, sankoachaea wrote in the 7th comment:
Votes: 0
Like genone suggested, I would generally start with the first element, then append the delimiter to each following element before writing them. Here's an example in Lua, but of course I'm cheating. The function getn(t) is already provided to determine the size of my array.

function strjoin(delimiter, list)
local len = getn(list)
if len == 0 then
return ""
end
local string = list[1]
for i = 2, len do
string = string .. delimiter .. list[i]
end
return string
end


strjoin("and ", {"Mario", "Luigi", "Megatron", "Dan Quale"})  –> Mario and Luigi and Megatron and Dan Quale


Edit: The underlying mechanics of joins are usually only really important to me when I need to do splits/inverse.
18 Feb, 2011, David Haley wrote in the 8th comment:
Votes: 0
Here's another interesting read on this subject: string buffers in Lua (from the book Programming in Lua). In particular note that "obvious" string concatenation can have terrible performance implications. This is basically a delimiter-less join; it should be pretty clear how to make it work with delimiters as well.

This problem can get interesting when you don't know ahead of time how big your list is. This is the case if you are joining elements obtained from an iterator, for example: there is typically no way to query an iterator for the number of elements. (Some iterators that consume data from input like network or stdin simply have no way of knowing.) In this case, you need to keep retrieving things from the iterator until it expires… it doesn't look that different from what Sanko posted:

cur = get_from_iterator()

if cur is null:
return ""
else:
result = cur

while cur = get_from_iterator() is not null:
result = result + delim + cur


of course this ignores the stuff I was just talking about w.r.t. efficient string concatenation.

I make no claims as to the efficiency of the above. :smile:
18 Feb, 2011, sankoachaea wrote in the 9th comment:
Votes: 0
Oh, I should also note that the example I gave is effectively an implementation of Perl's join() (in Lua).
0.0/9