I know you already got an answer, but I read your question yesterday before going to the beach and I imagined this one while I was looking at the kite surf "ballet", so I give it, it is a little bit different than Steve one, so it may be interesting.
The lists:map function cannot be used in the case of this analysis, because it only apply a given function to each elements of a list to build a new list which will have the same length. No way to build nested list. As @Steve says, you need an accumulator to progressively build the results.
The lists library offers a function to accumulate terms while traversing a list: lists:foldl/3 (it exists also foldr, mapfoldl and mapfoldr), the problem in this case is to define the accumulator that will help us to build the expected result.
The simplest list to analyze have no parenthesis, so the accumulator should contain a list where to accumulate all the elements of the entry list.
But if we encounter a "(", we should start a new list that will contain the sublist we have to nest in the result. In this case we need a term that contain a list were we can put the new sublist to build, and the list that was in progress when we encounter the "(".
the simplest structure that can fit the 2 needs in a single form is a list of list: [SublistInProgress|PreviousWork]
Now we know the form of our accumulator, we can define the function in charge to build it, 3 cases:
- we find a "(": start a new sublist, and and "store" the previous accumulator
- we find a ")": add the sublist to the previous accumulator
- any other case add the element to the sublist in progress.
in the shell :
1> F = fun("(",Acc)-> [[],Acc];
1> (")",[SubList,[Hacc|Tacc]]) -> [[lists:reverse(SubList)|Hacc]|Tacc];
1> (X,[Hacc|Tacc]) -> [[X|Hacc]|Tacc] end.
#Fun<erl_eval.12.52032458>
Note: I accumulate the element in the list using the construct [X|Hacc]
rather than Hacc ++ [X]
, it is a good habit because it avoids to make a completely new list at each step (and doing this I will avoid a remark from my friend @Hynek-Pichi-Vychodil :o). So I have to reverse the list when I want to store it.
Using F in the function lists:foldl(F,[[]],L)
we will get a list of one element, this element is the reverse of the expected result. So we have to embed this call to the library in a specific function:
2> Transform = fun(L) -> [R] = lists:foldl(F,[[]],L),
2> lists:reverse(R) end.
#Fun<erl_eval.6.52032458>
and we can test it:
3> L1 = ["0", "(", "1", "2", "3", ")"].
["0","(","1","2","3",")"]
4> L2 = ["0", "(", "11", "22", "(", "333", "444","(", "5555", ")", "666", ")", "77", "88", ")", "9"].
["0","(","11","22","(","333","444","(","5555",")","666",")",
"77","88",")","9"]
5> Transform(L1).
["0",["1","2","3"]]
6> Transform(L2).
["0",["11","22",["333","444",["5555"],"666"],"77","88"],"9"]