Erlang : flattening a list of strings
I have a list like this:
[["str1","str2"],["str3","str4"],["str5","str6"]]
And I need to convert it to
["str1", "str2", "str3", "str4", "str5", "str6"]
How do I do this?
The problem is that I'm dealing with lists of strings, so when I do
lists:flatten([["str1","str2"],["str3","str4"],["str5","str6"]])
I get
"str1str2str3str4str5str6"
However, if the elements of the original list where just atoms, then list开发者_StackOverflow社区s:flatten
would have given me what I needed. How do I achieve the same with strings?
lists:append does exactly what you need:
1> lists:append([["str1","str2"],["str3","str4"],["str5","str6"]]).
["str1","str2","str3","str4","str5","str6"]
(lists:concat does the right thing, but threatens to do some type conversion too.)
If your list is always a "list of list of string", then you can simply use the foldl
operator, with something like:
Flat = list:foldl(fun(X, Acc) -> X ++ Acc end, [], List)
In the case your list nesting can be of arbitrary depth, I would rather suggest to let erlang know your strings are not mere character lists, using an encoding such as:
[[{string, "str1"},{string, "str2"}],
[{string, "str3"}, {string, "str4"}],
[{string, "str5"},{string, "str6"}]]
This way, list:flatten
will do the right thing, and give:
[{string, "str1"},{string, "str2"},
{string, "str3"}, {string, "str4"},
{string, "str5"},{string, "str6"}]
which you can convert back if needed to a raw list of strings using foldl
.
If your strings are to be handled differently from mere character lists, then they probably deserve to be a real data structure, see this blog entry for an interesting discussion on this matter.
lists:concat/1 works...
The reason lists:flatten doesn't work for you is that strings in Erlang are just lists of small integers. We can handle this with a function that stops recursing down in a nested list if the list is just a string.
For arbitrarily nested list of strings you can use the following function:
slab([]) ->
[];
slab([F|R]) ->
case io_lib:char_list(F) of
true -> [F|slab(R)];
false -> slab(F) ++ slab(R)
end.
It uses io_lib:char_list() to decide if the nesting recursion was deep enough.
Exampe of operation:
1> slab([[["foo", "bar"], "baz", [[[["foobar"]]]], "froboz", "the end"]]).
["foo","bar","baz","foobar","froboz","the end"]
2>
A small improvement that would make it possible to use mixed nested lists:
slab([]) ->
[];
slab([F|R]) when is_list(F) ->
case io_lib:char_list(F) of
true -> [F|slab(R)];
false -> slab(F) ++ slab(R)
end;
slab([F|R]) ->
[F|slab(R)].
This behaves just like lists:flatten except that it handles string as if they would be no lists:
1> slab([[["foo", "bar"], "baz", [[[["foobar", atom]],[a,b,c]]], 2, "froboz", "the end"]]).
["foo","bar","baz","foobar",atom,a,b,c,2,"froboz","the end"]
精彩评论