I'm trying to learn recursion in Erlang and I am working through a book. But I'm hitting a wall when faced with the problem of taking a list and returning only the duplicate elements. I tried writing a function which returns only the unique elements and then removing them from the original list.
adjacent_dups(L) -> L -- uniques(L).
uniques([]) -> [];
uniques([H|T]) -> [H | [X || X <- uniques(T), X /= H]].
This will however not give the correct result when the list is not well structured.
L = [7,3,4,3]
My code will return
adjacent_dups([7,3,4,3]) -> 3
How can I get
adjacent_dups([7,3,4,3]) -> []
Use pattern matching in the function head to find adjacent identical values:
adjacent_dups(L) ->
adjacent_dups(L, #{}).
adjacent_dups([], Acc) ->
maps:keys(Acc);
adjacent_dups([H,H|T], Acc) ->
adjacent_dups(T,maps:put(H,H,Acc));
adjacent_dups([_|T], Acc) ->
adjacent_dups(T, Acc).
The first function adjacent_dups/1
is meant to be exported. The rest, adjacent_dups/2
, are helper functions.
The adjacent_dups/1
function creates an empty map to pass to adjacent_dups/2
as the initial value of an accumulator. Recursive functions often use accumulators.
The first clause of adjacent_dups/2
handles the case where the incoming list has been exhausted or was empty to start with. In that case, we retrieve the keys of the accumulator map; these are our adjacent values.
The second clause of adjacent_dups/2
handles the case of adjacent values using pattern matching. In this case, we add the value as a key and value to the accumulator map, and call ourselves recursively with the tail of the list. Using a map eliminates duplicates from the final result.
The final clause of adjacent_dups/2
handles the case where a value does not have an adjacent value; it simply makes a recursive call with the tail of the list and an unmodified accumulator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With