I'm making a function with recursion that adds element A after element of list which equals B. So it should look like this:
func(20,4,[1,2,4,5,4]) -> [1,2,4,20,5,4,20]
This is what I've got:
-module (task).
-export ([vst/3]).
vst(A,B,[]) -> 0;
vst(A,B,[H|T]) when H=:=B -> [H,A|T)].
How I should do this with recursion?
Three things:
You need to return [] in the base case.
You need to recursively call vst in H=:=B case.
You need to handle the case when H=/=B.
Final code:
vst(_A, _B, []) -> [];
vst(A, B, [H|T]) when H =:= B -> [H, A | vst(A, B, T)];
vst(A, B, [H|T]) -> [H | vst(A, B, T)].
1> task:vst(20, 4, [1,2,4,5,4]).
[1,2,4,20,5,4,20]
2> task:vst(20, 4, [4,4,4]).
[4,20,4,20,4,20]
3> task:vst(20, 4, []).
[]
Related
I accidentally did (the equivalent of) the following:
lists:foldl(fun(X, Acc) -> [X|Acc] end, 0, List).
Note the not-a-list initial value for the accumulator.
This resulted in an improper list. This means that length, etc., don't work on it.
Given that my "equivalent of" took an hour to run, and I don't want to run it again, how do I repair my improper list?
For a simpler example of an improper list and the problem that it causes:
1> L = [1|[2|[3|4]]].
[1,2,3|4]
2> length(L).
** exception error: bad argument
in function length/1
called as length([1,2,3|4])
If you want to preserve the "improper tail", this would be enough:
Fix = fun Fix([H | T]) -> [H | Fix(T)];
Fix(T) -> [T]
end.
Here is a possible approach:
Lister = fun L([], Acc) -> lists:reverse(Acc);
L([[_ | _] = H | T], Acc) -> L(T, [L(H, []) | Acc]);
L([[] | T], Acc) -> L(T, Acc);
L([H | T], Acc) -> L(T, [H | Acc]);
L(X, Acc) -> L([], [X | Acc])
end.
L = [[[1,[1|2]],1|2],1|[2|[3|4]]].
Lister(L, []).
% output [[[1,[1,2]],1,2],1,2,3,4]
For the simple case I had, with non-nested improper list, where I don't want the extra item (because it should have been an empty list and doesn't mean anything), this'll do it:
Fix = fun F([H|T], A) when is_list(T) -> F(T, [H|A]);
F([H|_], A) -> F([], [H|A]);
F([], A) -> lists:reverse(A)
end.
Fix(L, []).
you must use list for ACC
lists:foldl(fun(X, Acc) -> [X|Acc] end, 0, [1,2,3]).
result => [3,2,1|0]
but if you use [0] for ACC argument in lists:foldl/3 function like bellow
lists:foldl(fun(X, Acc) -> [X|Acc] end, [0], [1,2,3]).
result => [3,2,1,0]
Im working on some erlang functions and im also not allowed to use library functions. I have to define a function that drops every other element from a list, starting with the first element.
I have worked on something similar before but i could use BIFs and now i am struggling.
For example, alternate([1,2,3,four,5,6]) is [2,four,6]. I am not sure how to implement it.
spec drop_word(string()) -> string().
drop_word([]) -> [];
drop_word([O|Op]) -> case wsp(O) of
true -> Op;
false -> drop_word(Op)
end.
alternate(List) ->
alternate(List, _Index=0).
alternate([_|T], Index) when Index rem 2 == 0 -> %even indexes
alternate(T, Index+1);
alternate([H|T], Index) when Index rem 2 == 1 -> %odd indexes
[H | alternate(T, Index+1)];
alternate([], _Index) ->
[].
In the shell:
12> a:alternate([1,2,3,four,5,6]).
[2,four,6]
13> a:alternate([1,2,3,four,5]).
[2,four]
But, that can be simplified to:
alternate(List) ->
evens(List).
evens([_|T]) ->
odds(T);
evens([]) -> [].
odds([H|T]) ->
[H | evens(T)];
odds([]) -> [].
In the shell:
6> a:alternate([1,2,3,four,5,6]).
[2,four,6]
7> a:alternate([1,2,3,four,5]).
[2,four]
Here's an accumulator version:
alternate(List) ->
evens(List, []).
evens([_|T], Acc) ->
odds(T, Acc);
evens([], Acc) ->
lists:reverse(Acc).
odds([H|T], Acc) ->
evens(T, [H|Acc]);
odds([], Acc) ->
lists:reverse(Acc).
In the shell:
20> a:alternate([1,2,3,four,5,6]).
[2,four,6]
21> a:alternate([1,2,3,four,5]).
[2,four]
Note that lists:reverse() is highly optimized, so you would never do List ++ [X] many times, which traverses the whole list every time you add an element to the end of the list. Rather, you should always choose to add an element to the head of a list, then call lists:reverse(). Oh yeah, no library functions...a reverse() function is easy to implement yourself, and although it won't be optimized like the erlang version, it will still be more efficient than doing List ++ [X] multiple times.
You can use two atoms drop and keep two match the alternating clauses of do_alternate. Details below in comments.
-module(so).
-export([alternate/1]).
% The exported function starts the actual function and tells it to match the `drop`
% clause. Kept elements of L will be collected in the third argument.
alternate(L) -> do_alternate(drop, L, []).
% The `drop` clause will call the `keep` clause and pass the tail T and the
% currently collected list Acc. The head H will be dropped.
do_alternate(drop, [_|T], Acc) -> do_alternate(keep, T, Acc);
% The `keep` clause will call the `drop` claues and pass the tail T and the
% currently collected list Acc with the head H prepented to it.
do_alternate(keep, [H|T], Acc) -> do_alternate(drop, T, Acc ++ [H]);
% If the arugment list is empty, return the accumulated list.
do_alternate(_, [], Acc) -> Acc.
Example usage:
> c(so).
{ok,so}
9> so:alternate([1,2,3,4,5,6]).
[2,4,6]
10> so:alternate([1,2,3,4,5,6,seven,eight,nine,ten,eleven]).
[2,4,6,eight,ten]
It seems that you want to drop any elements with position which is even. So you can do it like below:
-module(test).
-compile([export_all,debug_info]).
alternate(L) -> do_alternate(L, 0, length(L)).
do_alternate(_, L, L) -> [];
do_alternate([H|T], N, L) ->
case (N band 1) == 0 of
true -> do_alternate(T, N+1, L);
false -> [H] ++ do_alternate(T, N+1, L)
end.
Result in shell:
1> c(test).
test.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,test}
2> test:alternate([1,2,3,four,5,6]).
[2,four,6]
Moreover, if your List only has integer numbers, so you can use BIF like below:
3> lists:partition(fun(A) -> A rem 2 == 1 end, [1,2,3,4,5,6]).
{[1,3,5],[2,4,6]}
You could pattern match on the list, taking two elements at a time:
alternate([_Odd, Even | T]) ->
[Even] ++ alternate(T);
alternate([]) ->
[].
The specification doesn't say what happens if the list has an odd number of elements, so this function will just crash with a "function clause" error in that case. You could add a third clause to handle that - presumably dropping the last element would be a sensible thing to do:
alternate([_Last]) ->
[];
I would like to use the below Erlang code to get the highest integer in a list of integers but for some reason always end up getting the last integer in the list. Any help?
Solution example -> test:max([2,8,5,6]). should return 8 but with this code it returns 6.
-spec max(L) -> M when
L::[integer()],
M::integer().
max([H | T]) ->
F = fun(L, Acc) -> max([L]) end,
lists:foldl(F, H, T).
Your function F should return the max of L and Acc. You can use the builtin max/2 function for that:
...
F = fun(L, Acc) -> max(L, Acc) end.
...
Test:
1> F = fun(L, Acc) -> max(L, Acc) end.
#Fun<erl_eval.12.52032458>
2> [H | T] = [2, 8, 5, 6].
[2,8,5,6]
3> lists:foldl(F, H, T).
8
What you return in your function F will be the new value of Acc, and eventually the value lists:foldl/3 will return.
What you may want to do is do comparison inside F and check if Acc is greater than the current value. You don't need to recurse max/1 since you're iterating the list in lists:foldl/3 anyway.
Let me know if you need the actual code right away, but I would recommend figuring it out yourself. It's more fun for you that way.
I have a list in erlang containing interger values.
I want to remove values that occur only one time.(Not Duplicates).
Input = [1,3,2,1,2,2]
Output = [1,2,1,2,2]
I am newbie to erlang. I have tried an approach to sorting them first using list:sort() and then removing a member if the member next to it is the same.
I am having trouble trying to iterate the list. It would be great help if you can show me how I can do it.
multiple(L) ->
M = L -- lists:usort(L),
[X || X <- L , lists:member(X,M)].
Use map to count values and then filter values which was not present just once.
-module(test).
-export([remove_unique/1]).
remove_unique(L) ->
Count = lists:foldl(fun count/2, #{}, L),
lists:filter(fun(X) -> maps:get(X, Count) =/= 1 end, L).
count(X, M) ->
maps:put(X, maps:get(X, M, 0) + 1, M).
And test:
1> c(test).
{ok,test}
2> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[3,3,3,5,5,7,7]
3> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[3,3,3,5,5]
4> test:remove_unique([1,3,2,1,2,2]).
[1,2,1,2,2]
Here's a solution I'd written when first seeing the question when posted, that uses the same logic as #A.Sarid's recursion/pattern matching answer, except that I use a "Last" parameter instead of the count.
-module(only_dupes).
-export([process/1]).
process([]) -> [];
process(L) when is_list(L) ->
[H|T] = lists:sort(L),
lists:sort(process(undefined, H, T, [])).
process(Last, Curr, [], Acc)
when Curr =/= Last ->
Acc;
process(_Last, Curr, [], Acc) ->
[Curr | Acc];
process(Last, Curr, [Next | Rest], Acc)
when Curr =/= Last, Curr =/= Next ->
process(Curr, Next, Rest, Acc);
process(_Last, Curr, [Next | Rest], Acc) ->
process(Curr, Next, Rest, [Curr | Acc]).
One way for iterating a list (that as a result will return a new list) is using recursion and pattern matching.
After you sort your list you want to iterate the list and to check not only that it is different from the next element, but that there was no other equal elements before it. Consider the list [3,3,3,5,5] if you will only check the next element, the last 3 will also be unique and that is incorrect.
Here is a working program, I used a counter to cover the above case as well. See the syntax for using [H|T] for iterating over the list. You may see more cases and read more about it here.
-module(test).
-export([remove_unique/1]).
remove_unique(Input) ->
Sorted = lists:sort(Input),
remove_unique(Sorted, [], 0).
% Base case - checks if element is unique
remove_unique([H|[]],Output,Count) ->
case Count of
0 -> Output;
_Other -> [H|Output]
end;
% Count is 0 - might be unique - check with next element
remove_unique([H1|[H2|T]],Output, 0)->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],1);
false -> remove_unique([H2|T],Output,0)
end;
% Count is > 0 - not unique - proceed adding to list until next value
remove_unique([H1|[H2|T]],Output,Count) ->
case (H1 =:= H2) of
true -> remove_unique([H2|T],[H1|Output],Count+1);
false -> remove_unique([H2|T],[H1|Output],0)
end.
Test
7> test:remove_unique([1,2,3,3,3,5,5,6,7,7]).
[7,7,5,5,3,3,3]
8> test:remove_unique([1,2,3,3,3,5,5,6,7,8]).
[5,5,3,3,3]
I have the following List structure:
[{A, [{B <--, [A, C]}, {C <--, [B, A]}]}, {B, [{C <--, [A, C]}]}]
For example, B = 1, C = 2.
What would be the correct way to do so?
UPDATE
I'd like to count the number of <-- (a symbol I added just to show what I'm referring to) pointed item in it.
It can be implemented in many ways. Here is one more.
count(List) ->
count(List, dict:new()).
count([{_, InList} | Rest], Dict) ->
count(Rest, count2(InList, Dict));
count([], Dict) ->
dict:to_list(Dict).
count2([{Symbol, _} | Rest], Dict) ->
count2(Rest, dict:update_counter(Symbol, 1, Dict));
count2([], Dict) ->
Dict.
Example Output:
1> test:count([{one, [{b, [123]}, {c,[123]}, {b,[123]}]}, {two, [{b, [123]}, {c,[123]}, {b,[123]}]}]).
[{b,4},{c,2}]
You can write a simple code using an accumulator and some list functions. Supposing all list elements are of the same format:
count(L) ->
count (L, []).
count ([], Cases) ->
Cases;
count ([{_E1, [{X, [_E2, _E3]}]} | Rest], Cases) ->
NewCases =
case lists:keysearch(X, 1, Cases) of
false ->
[ {X, 1} | Cases ];
{value, {X, Val}} ->
lists:keyreplace(X, 1, Cases, {X, 1+Val})
end,
count(Rest, NewCases).