21 June 2007

Join and split

It always amazes me when I try out a new programming language and find that the standard library doesn't include join and split functions. join is used to combine a list of strings into a single string with each item separated by a delimiter. split takes a delimited string and divides it into sub-strings. Python, thankfully, does provide these functions:

>>> ':'.join(['a','b','c'])
'a:b:c'
>>> 'a:b:c'.split(':')
['a', 'b', 'c']

Erlang provides regexp:split but it looks like I have to add my own join function. Not sure this is the most efficient implementation but it will do the job:
intersperse(_, []) -> [];
intersperse(Element, List) ->
tl(lists:reverse(lists:foldl(fun(X, A) -> [X,Element|A] end, [], List))).

join(List, ListOfLists) -> lists:append(intersperse(List, ListOfLists)).

> intersperse(":", ["a","b","c"]).
["a",":","b",":","c"]
> join(":", ["a","b","c"]).
"a:b:c"

And since strings in Erlang are just lists of integers this can be applied to other lists as well.

4 comments:

maport said...

Comment from Christian S:

Intersperse would be a fine addition to the 'lists'-
module. This is however the way i would express it:


-module(intersperse).
-export([intersperse/2, join/2]).

intersperse(_, []) ->
[];
intersperse(Delimiter, [Head|Rest]) ->
intersperse(Delimiter, Rest, [Head]).

intersperse(_Delimiter, [], Acc) ->
lists:reverse(Acc);
intersperse(Delimiter, [Head|Rest], Acc0) ->
Acc1 = [Head, Delimiter|Acc0],
intersperse(Delimiter, Rest, Acc1).

%% The need for this function is questionable, the name
%% join is also questionable as it is also the
%% name of a relational-db operation.
join(Delimiter, List) ->
lists:flatten(intersperse(Delimiter, List)).

maport said...

Comment from Michael Le Du:

You can use string:tokens("a:b:b", ":"). to split the string

maport said...

Comment from puzza007:

Here's my version of join. I can't believe that the lists module doesn't already have one!

join(List, Sep) ->
join(List, Sep, []).
join([H|T], Sep, Acc) ->
join(T, Sep, [H,Sep|Acc]);
join([], _Sep, Acc) ->
lists:reverse(Acc).

maport said...

Comment from puzza007:

Er, no. Just tested that. Second time's a charm:


join([E1, E2| Es], S) ->
[E1, S| join([E2| Es], S)];
join([E], _) ->
[E];
join([], _) ->
[].