The problem I am trying to solve states
Write a function map_search_pred(Map, Pred) that returns the first
element {Key,Value} in the map for which Pred(Key, Value) is true.
My attempt looks like
map_search_pred(#{}, _) -> {};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
When I run this, I see output as
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
2> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{}
3> maps:size(#{}).
0
4>
How am I so sure?
I pulled out the first clause so it looks like
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
and run again
1> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{1,1}
2> lib_misc:map_search_pred(#{}, fun(X, Y) -> X =:= Y end).
** exception error: no match of right hand side value []
in function lib_misc:map_search_pred/2 (/Users/harith/code/IdeaProjects/others/erlang/programmingErlang/src/lib_misc.erl, line 42)
3>
According to map documentation:
Matching an expression against an empty map literal will match its type but no variables will be bound:
#{} = Expr
This expression will match if the expression Expr is of type map, otherwise it will fail with an exception badmatch.
However erlang:map_size can be used instead:
map_search_pred(Map, _) when map_size(Map) == 0 ->
{};
map_search_pred(Map, Pred) ->
[H|_] = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
H.
Related
Suppose I have a map like this
A = #{a=>1,b=>2,c=>3}.
I want to create a function which converts A to a list of tuples of key-value pairs.
list = [{a,1},{b,2},{c,3}]
maps:to_list/1 does exactly this:
1> maps:to_list(#{a=>1,b=>2,c=>3}).
[{a,1},{b,2},{c,3}]
You can use maps:fold/3 for loop map items. Let's say you need just convert a map, then you can use something like:
1> A = #{a=>1,b=>2,c=>3}.
2> maps:fold(
fun(K, V, Acc) ->
[{K, V} | Acc]
end,
[], A).
[{c,3},{b,2},{a,1}]
For case if need to do the same for nested maps, this example can be modify like:
1> A = #{a => 1, b => 2, c => 3, d => #{a => 1, b => #{a => 1}}},
2> Nested =
fun F(K, V = #{}, Acc) -> [{K, maps:fold(F, [], V)} | Acc];
F(K, V, Acc) -> [{K, V} | Acc]
end,
3> maps:fold(Nested, [], A).
[{d,[{b,[{a,1}]},{a,1}]},{c,3},{b,2},{a,1}]
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 would like to divide a string to sub-strings based on a given number , for example:
divide("string",1) = ["s","t","r","i","n","g"].
I have tried this, but no success .
lists:split(1,"string") = {"s", "tring"}
Any idea?
I would calculate the length once (since it's a slow operation) and then recursively use lists:split/2 until the list left is smaller than N:
divide(List, N) ->
divide(List, N, length(List)).
divide(List, N, Length) when Length > N ->
{A, B} = lists:split(N, List),
[A | divide(B, N, Length - N)];
divide(List, _, _) ->
[List].
1> c(a).
{ok,a}
2> a:divide("string", 1).
["s","t","r","i","n","g"]
3> a:divide("string", 2).
["st","ri","ng"]
4> a:divide("string", 3).
["str","ing"]
5> a:divide("string", 4).
["stri","ng"]
6> a:divide("string", 5).
["strin","g"]
7> a:divide("string", 6).
["string"]
8> a:divide("string", 7).
["string"]
I think #Dogbert solution is currently the best... But here an other implementation example with recursive loop.
divide_test() ->
[?assertEqual(divide("string",1), ["s","t","r","i","n","g"]),
?assertEqual(divide("string",2), ["st","ri","ng"]),
?assertEqual(divide("string",3), ["str","ing"]),
?assertEqual(divide("string",4), ["stri","ng"])
].
-spec divide(list(), integer()) -> list(list()).
divide(String, Size)
when is_list(String), is_integer(Size) ->
divide(String, Size, 0, [], []).
-spec divide(list(), integer(), integer(), list(), list()) -> list(list()).
divide([], _, _, Buf, Result) ->
Return = [lists:reverse(Buf)] ++ Result,
lists:reverse(Return);
divide([H|T], Size, 0, Buf, Result) ->
divide(T, Size, 1, [H] ++ Buf, Result);
divide([H|T], Size, Counter, Buf, Result) ->
case Counter rem Size =:= 0 of
true ->
divide(T, Size, Counter+1, [H] ++ [], [lists:reverse(Buf)] ++ Result);
false ->
divide(T, Size, Counter+1, [H] ++ Buf, Result)
end.
You can try this function. provided the number is > 0 less than or equal to string length divided by two.
first_substring(List, Separator) ->
first_substring_loop(List, Separator, []).
first_substring_loop([], _, Reversed_First) ->
lists:reverse(Reversed_First);
first_substring_loop(List, Separator, Reversed_First) ->
[H|T]= my_tuple_to_list(lists:split(Separator,List)),
first_substring_loop(lists:flatten(T), Separator, [H|Reversed_First]).
my_tuple_to_list(Tuple) -> [element(T, Tuple) || T <- lists:seq(1, tuple_size(Tuple))].
the result is
1> fact:first_substring("string", 1).
["s","t","r","i","n","g"]
2> fact:first_substring("string", 2).
["st","ri","ng"]
3> fact:first_substring("string", 3).
["str","ing"]
A short simple solution can be:
divide(String, Length) -> divide(String, Length, []).
divide([], _, Acc) -> Acc;
divide(String, Length, Acc) ->
{Res, Rest} = lists:split(min(Length, length(String)), String),
divide(Rest, Length, Acc ++ [Res]).
Also for a specific case of splitting with length 1, a list comprehension can be used:
ListOfLetters = [[Letter] || Letter <- String].
The more formal definition of problem is
Write a function map_search_pred(Map, Pred) that returns the first
element {Key,Value} in the map for which Pred(Key, Value) is true.
My attempt, looks like
map_search_pred(Map, Pred) ->
M = [{Key, Value} || {Key, Value} <- maps:to_list(Map), Pred(Key, Value) =:= true],
case length(M) of
0 -> {};
_ -> lists:nth(1, M)
end.
When I run this, I get correct answer
1> lib_misc:map_search_pred(#{}, fun(X, Y) -> X =:= Y end).
{}
2> lib_misc:map_search_pred(#{1 => 1, 2 => 2}, fun(X, Y) -> X =:= Y end).
{1,1}
3> lib_misc:map_search_pred(#{1 => 1, 2 => 3}, fun(X, Y) -> X =:= Y end).
{1,1}
4> lib_misc:map_search_pred(#{1 => 2, 2 => 2}, fun(X, Y) -> X =:= Y end).
{2,2}
5>
Problem?
The problem is efficiency.
It uses list comprehension and runs for all the elements in the list. The better solution would be to return after the first match.
As a beginner to language, I do not know a better idiomatic way to solve this, so looking for better ideas and suggestions
You could walk the list yourself and return as soon as you find an element for which Pred(Key, Value) is true:
map_search_pred(Map, Pred) when is_map(Map) ->
map_search_pred(maps:to_list(Map), Pred);
map_search_pred([], _) ->
error;
map_search_pred([{Key,Value}=H|T], Pred) ->
case Pred(Key, Value) of
true ->
{ok, H};
false ->
map_search_pred(T, Pred)
end.
I have a piece of code that goes like this:
Fi_F = fun (F, I, Xs) ->
fun ( X ) ->
F( x_to_list(X, Xs, I) )
end
end,
I just need to turn a function of list to a function of one number. For example with Xs = [1,2,3] and I = 2, I expect this to grant me with function:
fun ( X ) -> F([ 1, X, 3]) end.
But somehow F, I and X are shadowed, not closured, so it fails in x_to_list with an empty list.
I'm still new to Erlang and think I'm missing something more conceptual, than a mere syntax problem.
UPD: Found a bug. I wrote x_to_list/3 this way:
x_to_list( X, L, I ) ->
lists:sublist(L, I) ++ [ X ] ++ lists:nthtail(I+1, L).
So it counts list elements from 0, not 1. When I call it with I = 3, it fails. So this is not about closuring.
I still have shadowing warnings though, but it is completely another issue.
A somewhat quick and dirty implementation of x_to_list/3 (just to test) would be:
x_to_list(X, Xs, I) ->
{ Pre, Post } = lists:split(I-1, Xs),
Pre ++ [X] ++ tl(Post).
Then, your code works without problems:
> Q = fun ( F, I, Xs ) -> fun (X) -> F( x_to_list(X, Xs, I)) end end.
> Y = Q( fun(L) -> io:format("~p, ~p, ~p~n", L) end, 2, [1,2,3] ).
> Y(4).
1, 4, 3
ok