2010-11-22 27 views
1

J'ai une liste d'articles que je voudrais "un-zip-aplatir". Fondamentalement, ce que cela signifie est que si j'ai une liste d'éléments:Erlang un-zip-flatten

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

Je veux en faire une liste de listes comme les suivantes:

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

Jusqu'à présent, ma solution ressemble à ceci:

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)). 

Je suis assez nouveau pour Erlang Je suis tellement me demandant si je l'ai raté une fonction de bibliothèque standard qui ferait ce que je veux, ou s'il y a une façon plus « Erlangish » de le faire, ou si la performance de mon ci-dessus la solution pue.

Répondre

2

Je pense que ce serait une méthode plus « Erlangish » pour le faire. Fondamentalement, vous créez la liste des listes qui seront votre résultat, et utilisez deux listes pour gérer ces listes comme une file d'attente. La liste "Heads" contient les listes que vous allez ajouter à la liste suivante, et la liste "Tails" est celle qui vient d'être ajoutée. Lorsque Heads est vide, vous inversez simplement Tails et l'utilisez comme nouveau Heads. Avant de renvoyer le résultat, vous devrez inverser toutes les listes dans Tails et Heads, puis ajouter Heads tel quel aux Tails inversés. Excusez les noms de variables confus, je pense venir avec plusieurs bons noms pour briser les listes dans un programme Erlang est le plus difficile;)

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]). 

Il est également possible de faire la phase « dézipper » dans un non de queue façon récursive d'éviter les listes: marche arrière, mais c'est une solution plus compliquée. Quelque chose comme ceci:

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

Oui, les performances vont puer (conseil de base pour l'utilisation lists:nth: ne jamais l'appeler plusieurs fois avec la croissance N!). Quelque chose comme cela devrait être mieux (non testé):

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).