2015-07-14 10 views
1

Учитывая список и целое число, я хочу разбить этот список на указанное количество списков (внутри списка).Как разбить список строк на заданное количество списков в erlang

Например:

Вход:

[1,2,3,4,5,6,7,8,9], 3 

Выход:

[[1,2,3],[4,5,6],[7,8,9]] 

Что такое чистый и эффективный способ сделать это?

ответ

4

solution, написанный Steve Vinoski, вызывает length/1 в качестве защиты для каждого раздела, что делает его O(N^2). Меня это просто беспокоит, потому что это можно сделать в O(N), и я работаю. Это может быть сделано во многих отношениях так просто, например, есть один:

divide(L, N) when is_integer(N), N > 0 -> 
    divide(N, 0, L, []). 

divide(_, _, [], Acc) -> 
    [lists:reverse(Acc)]; 
divide(N, N, L, Acc) -> 
    [lists:reverse(Acc) | divide(N, 0, L, [])]; 
divide(N, X, [H|T], Acc) -> 
    divide(N, X+1, T, [H|Acc]). 

или как модификация решения Стива

divide(L, N) -> 
    divide(L, N, []). 

divide([], _, Acc) -> 
    lists:reverse(Acc); 
divide(L, N, Acc) -> 
    try lists:split(N, L) of 
     {H,T} -> divide(T, N, [H|Acc]) 
    catch 
     error:badarg -> 
      lists:reverse([L|Acc]) 
    end. 

или еще проще:

divide([], _) -> []; 
divide(L, N) -> 
    try lists:split(N, L) of 
     {H,T} -> [H|divide(T, N)] 
    catch 
     error:badarg -> [L] 
    end. 
4

Вы можете использовать lists:split/2 для этого:

divide(L, N) -> 
    divide(L, N, []). 
divide([], _, Acc) -> 
    lists:reverse(Acc); 
divide(L, N, Acc) when length(L) < N -> 
    lists:reverse([L|Acc]); 
divide(L, N, Acc) -> 
    {H,T} = lists:split(N, L), 
    divide(T, N, [H|Acc]). 

Первая функция, divide/2, служит в качестве точки входа. Он просто вызывает вспомогательную функцию divide/3 с начальным значением аккумулятора пустого списка, а затем divide/3 выполняет всю работу. Первое предложение divide/3 соответствует тому, когда список был полностью обработан, поэтому он просто меняет память и возвращает это значение. Второе предложение обрабатывает случай, когда длина L меньше запрашиваемого значения N; он создает новый накопитель, добавляя Acc с L, а затем возвращая обратно этот новый аккумулятор. Третий пункт сначала вызывает lists:split/2, чтобы разбить входящий список на H, который является списком N элементов и T, остальная часть списка. Затем он называет себя рекурсивно, передавая T в качестве нового значения списка, оригинальное значение N и новый аккумулятор, состоящий из H в качестве первого элемента и оригинального аккумулятора, Acc, как хвост.

Смежные вопросы