2010-11-22 8 views
1

Ich habe eine Liste von Elementen, die ich "un-zip-flatten" möchte. Im Grunde, was das bedeutet, ist, dass wenn ich eine Liste der Elemente haben:Erlang un-zip-flatten

[[a, d, g], [b, e], [c, f]] 

Bisher meine Lösung sieht wie folgt aus:

[a, b, c, d, e, f, g] 

ich es in eine Liste von Listen wie folgt aktiviert werden soll:

unzipflatten(NumberOfLists, List) -> 
    lists:map(fun(Start) -> 
         lists:map(fun(N) -> 
             lists:nth(N, List) 
           end, 
           lists:seq(Start, length(List), NumberOfLists)) 
       end, 
       lists:seq(1, NumberOfLists)). 

ich bin ziemlich neu in Erlang so frage ich mich, wenn ich einige Standard-Library-Funktion verpasst haben, das tun würde, was ich will, oder ob es eine weitere „Erlangish“ Art und Weise, dies zu tun, oder wenn die Leistung meiner oben genannten Lösung wird stinken.

Antwort

2

Ich denke, das wäre eine mehr "Erlangish" Methode, dies zu tun. Im Grunde würden Sie die Liste der Listen erstellen, die Ihr Ergebnis sein wird, und zwei Listen verwenden, um diese Listen wie eine Warteschlange zu verwalten. Die "Heads" -Liste enthält die Listen, denen Sie als nächste vorangehen, und die "Tails" -Liste ist die Liste, der Sie zuletzt vorangehen. Wenn Heads leer ist, kehrt man Tails einfach um und benutzt sie als neue Heads. Bevor Sie das Ergebnis zurückgeben, müssen Sie alle Listen in Tails und Heads umkehren und dann die Köpfe an die umgekehrten Tails anhängen. Entschuldigen Sie die verwirrenden Variablennamen, ich glaube, komme mit mehreren guten Namen bis zum Abwracken Listen in einem Erlang-Programm ist der schwierigste Teil;)

unzipflatten(NumberOfLists, List) when NumberOfLists > 0 -> 
    unzipflatten(List, lists:duplicate(NumberOfLists, []), []). 

unzipflatten([], Heads, Tails) -> 
    [lists:reverse(L) || L <- lists:reverse(Tails, Heads)]; 
unzipflatten(L, [], Tails) -> 
    unzipflatten(L, lists:reverse(Tails), []); 
unzipflatten([Elem | Rest], [Head | Tail], Tails) -> 
    unzipflatten(Rest, Tail, [[Elem | Head] | Tails]). 

Es ist auch möglich, die „entpacken“ Phase in einem nicht Schwanz- zu tun rekursiver Weg, um die Listen zu vermeiden: umgekehrter Schritt, aber das ist eine kompliziertere Lösung. Etwas wie dieses:

unzipflatten(NumberOfLists, List) when NumberOfLists > 0 -> 
    unzipflatten({List, lists:duplicate(NumberOfLists, [])}). 

unzipflatten({[], Heads}) -> 
    [lists:reverse(L) || L <- Heads]; 
unzipflatten({L, Heads}) -> 
    unzipflatten(unzipper({L, Heads})). 

unzipper({[], Heads}) -> 
    {[], Heads}; 
unzipper({L, []}) -> 
    {L, []}; 
unzipper({[H | T], [Head | Tail]}) -> 
    {T1, Tail1} = unzipper({T, Tail}), 
    {T1, [[H | Head] | Tail1]}. 
0

Ja, die Leistung wird stinken (grundlegende Hinweise zur Verwendung lists:nth: Niemals mehrmals mit wachsender N anrufen!). So etwas sollte besser sein (nicht getestet):

unzipflatten(NumberOfLists, List) -> 
    unzipflatten(NumberOfLists, List, array:new(NumberOfLists, {default, []}), 0). 

unzipflatten(_, [], Lists, _) -> 
    lists:map(fun lists:reverse/1, array:to_list(Lists)); 
unzipflatten(NumberOfLists, [H | T], Lists, CurrentIndex) -> 
    NewLists = array:set(CurrentIndex, [H | array:get(CurrentIndex, Lists)], Lists), 
    unzipflatten(NumberOfLists, T, NewLists, (CurrentIndex + 1) rem NumberOfLists).