Erlang Central

Difference between revisions of "String join with"

From ErlangCentral Wiki

(New page: == Problem == You need to combine several items of a list into a string using a separator between each item representation. In python, this is done by: <code caption="Python example"> pyt...)
 
(added alternative solution code)
Line 31:Line 31:
 
erl> test:string_join(",", [1, 2, 3], fun(X) -> io_lib:format("~B", [X]) end).
 
erl> test:string_join(",", [1, 2, 3], fun(X) -> io_lib:format("~B", [X]) end).
 
"1,2,3"
 
"1,2,3"
 +
</code>
 +
 +
== Solution (alternative) ==
 +
There is another code which is simplier to read and works faster for me (goryachev):
 +
<code caption="Erlang code">
 +
my_string_join(Items, Sep) ->
 +
    lists:flatten(lists:reverse(my_string_join1(Items, Sep, []))).
 +
 +
my_string_join1([Head | []], _Sep, Acc) ->
 +
    [Head | Acc];
 +
my_string_join1([Head | Tail], Sep, Acc) ->
 +
    my_string_join1(Tail, Sep, [Sep, Head | Acc]).
 +
</code>
 +
 +
Usage:
 +
<code caption="Erlang code">
 +
erl> string_join:my_string_join(["123", "456", "789"], $,).               
 +
"123,456,789"
 +
</code>
 +
 +
 +
And here is a benchmark:
 +
<code caption="Erlang code">
 +
erl> Items = ["bar foo" || _ <- lists:seq(1, 100000)], ok.
 +
ok
 +
erl> {Time, _} = timer:tc(string_join, string_join, [",", Items]), Time.
 +
163565
 +
erl> {MyTime, _} = timer:tc(string_join, my_string_join, [Items, $,]), MyTime.
 +
87379
 
</code>
 
</code>
  
 
[[Category:CookBook]][[Category:StringRecipes]]
 
[[Category:CookBook]][[Category:StringRecipes]]

Revision as of 14:54, 15 August 2007

Problem

You need to combine several items of a list into a string using a separator between each item representation.

In python, this is done by:

python> ','.join(['a', 'b', 'c'])
'a,b,c'
python> ','.join(map(str, [1,2,3]))
'1,2,3'

Solution

This solution interleave the input list with as many copy of the separator, then use the builtin concat function to create the final string:

string_join(Join, L) ->
    string_join(Join, L, fun(E) -> E end).

string_join(_Join, L=[], _Conv) ->
    L;
string_join(Join, [H|Q], Conv) ->
    lists:flatten(lists:concat(
        [Conv(H)|lists:map(fun(E) -> [Join, Conv(E)] end, Q)]
    )).

Usage is as follow:

erl> test:string_join(",", ["1", "2", "3"]).
"1,2,3"
erl> test:string_join(",", [1, 2, 3], fun(X) -> io_lib:format("~B", [X]) end).
"1,2,3"

Solution (alternative)

There is another code which is simplier to read and works faster for me (goryachev):

my_string_join(Items, Sep) ->
    lists:flatten(lists:reverse(my_string_join1(Items, Sep, []))).

my_string_join1([Head | []], _Sep, Acc) ->
    [Head | Acc];
my_string_join1([Head | Tail], Sep, Acc) ->
    my_string_join1(Tail, Sep, [Sep, Head | Acc]).

Usage:

erl> string_join:my_string_join(["123", "456", "789"], $,).                 
"123,456,789"


And here is a benchmark:

erl> Items = ["bar foo" || _ <- lists:seq(1, 100000)], ok.
ok
erl> {Time, _} = timer:tc(string_join, string_join, [",", Items]), Time.
163565
erl> {MyTime, _} = timer:tc(string_join, my_string_join, [Items, $,]), MyTime.
87379