Erlang un-zip-flatten - PullRequest
       16

Erlang un-zip-flatten

1 голос
/ 22 ноября 2010

У меня есть список предметов, которые я хотел бы «распаковать».В основном это означает, что если у меня есть список элементов:

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

, я хочу превратить его в список списков, подобных следующему:

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

Пока что мое решениевыглядит так:

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

Я довольно новичок в Erlang, поэтому мне интересно, пропустил ли я какую-нибудь стандартную библиотечную функцию, которая бы делала то, что я хочу, или есть более "Erlangish" способчтобы сделать это, или если производительность моего решения выше воняет.

Ответы [ 2 ]

2 голосов
/ 23 ноября 2010

Я думаю, что это был бы более "Erlangish" метод, чтобы сделать это. По сути, вы должны создать список списков, который будет вашим результатом, и использовать два списка для управления этими списками, как очередь. Список «Головки» содержит списки, к которым вы будете добавлять следующие, а список «Хвостов» - те, к которым добавлены последние. Когда головы пустые, вы просто переворачиваете хвосты и используете их как новые головы. Перед возвратом результата вам нужно будет поменять местами все списки внутри Tails и Heads, а затем добавить Heads как есть к полностью измененным Tails. Извините за запутанные имена переменных, я думаю, что придумать несколько хороших имен для разбиения списков в программе Erlang - самая сложная часть;)

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

Также возможно выполнить фазу "распаковки" нерекурсивным способом, чтобы избежать списков: обратный шаг, но это более сложное решение. Примерно так:

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 голосов
/ 23 ноября 2010

Да, производительность будет вонять (основной совет по использованию lists:nth: никогда не вызывайте его несколько раз с ростом N!) Примерно так должно быть лучше (не проверено):

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