Erlang Programming Exercise: 3-5
This one was a four part exercise, so I've broken the file into sections.
-module(threefive). -export([filter/2, reverse/1, concatenate/1, flatten/1]).
Write a function that, given a list of integers and an integer, will return all integers smaller than or equal to that integer.
filter(Filtered, [], _Number) -> reverse(Filtered); filter(Filtered, [H|T], Number) when H =< Number -> filter([H|Filtered], T, Number); filter(Filtered, [_H|T], Number) -> filter(Filtered, T, Number). filter(List, Number) -> filter([], List, Number).
I'm using filter/2 as the interface function. It passes the arguments off to filter/3 which does the work. The extra argument that gets passed into filter/3 is the results list, and as you can see, it starts out empty. I ended up using that same pattern for all four of these exercises.
Write a function that, given a list, will reverse the order of the elements.
reverse(To, []) -> To; reverse(To, [H|T]) -> reverse([H|To], T). reverse(List) -> reverse([], List).
Reverse was the easiest of the four. You simply take the head from one list, and push it onto another list.
Write a function that, given a list of lists, will concatenate them.
concatenate(Dst, []) -> Dst; concatenate(Dst, [H|T]) -> concatenate([H|Dst], T). concatenateHelper(Dst, []) -> Dst; concatenateHelper(Dst, [H|T]) -> Dst2 = concatenate(Dst, H), concatenateHelper(Dst2, T). concatenate(Lists) -> reverse(concatenateHelper([], Lists)).
In order to concatenate, I take the items from the lists one at a time and add them to a result list. When we're all out of lists to copy items from, we're done. My function naming is a bit confusing. I have concatenate/1 calling concatenateHelper/2 which in turn calls concatenate/2.
Write a function that, given a list of nested lists, will return a flat list.
flattenHelper(Dst, []) -> Dst; flattenHelper(Dst, [H|T]) -> Dst2 = flattenHelper(Dst, H), flattenHelper(Dst2, T); flattenHelper(Dst, Item) -> [Item|Dst]. flatten(Lists) -> reverse(flattenHelper([], Lists)).
I don't like my solution for flatten, specifically lines 34-36. If I had a very deep structure to flatten it would consume a lot of stack space. I'll have to go back and optimize that for fun.
Cheers,
-Halzy
December 14th, 2010 - 09:02
Hi,
Nice job with the exercises
My observation is that the exercise with the concatenation is not tail-recursive.
I like to see your way of resolving after I first tried on my own.
So here is the tail-recursive version I wrote, since, probably, a lot of people is reading your site when they get to the exercises. I have tested it with the sample from the book.
concatenate([]) ->
[];
concatenate(ListOfLists) ->
concatenate_acc(ListOfLists, []).
concatenate_acc([], ConList) ->
lists:reverse(ConList);
concatenate_acc([H|T], ConList) ->
concatenate_acc(H, T, ConList).
concatenate_acc([H|T], Lists, ConList) ->
concatenate_acc(T, Lists, [H|ConList]);
concatenate_acc([], Lists, ConList) ->
concatenate_acc(Lists, ConList).
Andrei Marius
February 25th, 2011 - 08:44
Hi, I’m studying erlang too.
My version of concatenate use only two functions, but instead, the helper has one more case:
concatenate(Lists) ->
reverse(concatenateHelper(Lists, [])).
concatenateHelper([], Acc) -> Acc;
concatenateHelper([H | T], Acc) ->
Acc2 = concatenateHelper(H, Acc),
concatenateHelper(T, Acc2);
concatenateHelper(X, Acc) ->
[X | Acc].
Thinking about flatten, I realized that this can also be used to flatten a list.
concatenate([[1,[2,[3],[]]], [[[4]]], [5,6]]).
[1,2,3,4,5,6]
Do you think that my reasoning is correct?