tags:

views:

308

answers:

3

I have a list of tuples:

L = [{1, [a, b, c]}, {2, [d, e, f]}, {3, [[h, i, j], [k, l, m]]}]

this is what I have

lists:map(fun({_, B}-> B end, L).

the output is

[[a, b, c], [d, e, f], [[h, i, j], [k, l, m]]]

what I want is:

[[a, b, c], [d, e, f], [h, i, j], [k, l, m]]

it seems a pretty easy problem, but I can't figure out how to do it. Please help!

+2  A: 

For your specific example case, you can define the following function:

group3([], Acc) ->
     Acc;
group3([A,B,C|Tl], Acc) ->
    group3(Tl, [[A,B,C]] ++ Acc).

group3(L) ->
    lists:reverse(group3(L, [])).

and invoke it like this:

group3(lists:flatten(lists:map(fun({_, B}) -> B end, L))).

Hopefully that's enough to give you a general strategy.

Dustin
too bad it's supposed to take lists with length N. thanks for the effort
Quincy
+5  A: 

Let's see...

1> L = [{1, [a, b, c]}, {2, [d, e, f]}, {3, [[h, i, j], [k, l, m]]}].
[{1,[a,b,c]},{2,[d,e,f]},{3,[[h,i,j],[k,l,m]]}]

Trivial and straightforward, but not tail-recursive:

2> lists:foldr(fun ({_,[X|_]=E},A) when is_list(X) -> lists:append(A,E);
                   ({_,E},A) -> [E|A] end,
                [], L).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]

Not being tail-recursive is not very nice, though, but...

3> lists:reverse(lists:foldl(fun ({_,[X|_]=E},A) when is_list(X) ->
                                     lists:reverse(E,A);
                                 ({_,E},A) -> [E|A] end,
                             [], L)).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]

...the tail-recursive version also works (thanks to Zed for pointing out lists:reverse/2).

ndim
one question though, did you use lists:append(lists:reverse(E),A) then reverse the whole thing at the end, just to avoid appending result to the end of A all the time, to improve performance?
Quincy
@ndim: lists:reverse(E, A) =:= lists:append(lists:reverse(E), A)
Zed
@Quincy: Appending to the end of A requires traversing the list every time. That does not scale. So you build up lists in reverse, and do a single lists:reverse/1 call when it is complete. This is standard operating procedure in Erlang. Also, `lists:foldl/3`, unlike `lists:foldr/3`, is documented to use tail recursion and thus needs less stack and is faster due to walking through the list in the canonical direction. All in all, the `lists:foldl/3` solution should be the most robust.
ndim
@Quincy: Well, if you call it often with long lists of tuples containing long lists which need to be reversed, the `lists:foldr/3` solution might save some CPU cycles at the cost of some stack memory. You can design a load which works badly on most algorithms. :)
ndim
+1  A: 
-module(z).
-export([do/1]).

do([{_,[X|_] = L}|Tl]) when is_list(X) -> L ++ do(Tl);
do([{_, L}       |Tl])                 -> [L|do(Tl)];
do([])                                 -> [].

test:

1> z:do(L).
[[a,b,c],[d,e,f],[h,i,j],[k,l,m]]
Zed