Benjamin Halsted // [bgh] todo, add something clever here.

18Mar/102

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

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit
  • Twitter
Comments (2) Trackbacks (0)
  1. 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

  2. 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?


Leave a comment

(required)

No trackbacks yet.