An element in a tuple or not in erlang? - erlang

I'd like to know if there is a function in Erlang can help me know whether an element is in a tuple or not. Like sets:is_element/2.
Tuple = {aaa,bbb,ccc}.
is_element_of_tuple(Tuple, aaa) % => true
is_element_of_tuple(Tuple, ddd) % => false

You can always transform the tuple to a list using tuple_to_list/1:
is_element_of_tuple(Tuple, Element) ->
lists:member(Element, tuple_to_list(Tuple)).

The simple answer is: no there is no function to do this. You have to write your own loop which traverses all the elements of a tuple until it either finds or does not find it. You an either convert the tuple to a list as above or write your own loop, something like:
is_element_of_tuple(E, Tuple) ->
is_element_of_tuple(E, Tuple, 1, tuple_size(Tuple)).
is_element_of_tuple(E, T, I, S) when I =< S ->
case element(I, T) of
E -> true;
_ -> is_element_of_tuple(E, T, I+1, S)
end;
is_element_of_tuple(_, _, _, _) -> false. %Done all the elements
Using a case and matching in this way means we check for exact equality, and it is probably a little faster than using =:= and checking if that returns true or false.

Related

Find the minimum value in a map

I have a map organized as follows.Key is a simple term lets say an integer but the value is complex tuple {BB,CC,DD}. What is the best way to find the minimum CC in the map ? So far I have the following
-module(test).
-author("andre").
%% API
-export([init/0]).
init() ->
TheMap = build(maps:new(), 20),
io:format("Map: ~p~n", [TheMap]),
AKey = hd(maps:keys(TheMap)),
AValue = maps:get(AKey, TheMap),
maps:fold(fun my_min/3, {AKey, AValue}, TheMap).
build(MyMap, Count) when Count == 0 ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
my_min(Key, {A,B,C}, {MinKey, {AA,BB,CC}}) ->
if B < BB -> {Key, {A,B,C}};
B >= BB -> {MinKey, {AA,BB,CC}}
end.
My map is small so I am not too worried about the usage of AKey and AValue to find initial values for the fold, but I was wondering if there was a better way, or other data structure.
--
Thanks.
What you have is close to a good solution, but it can be improved. There's no need to dig out the first key and value to use an the initial value for the fold, since you can just pass an artificial value instead and make your fold function deal with it. Also, you can improve your use of pattern matching in function heads. Lastly, use start instead of init since that makes it easier to invoke when calling erl from the command line.
Here's an improved version:
-module(test).
-author("andre").
%% API
-export([start/0]).
start() ->
TheMap = build(maps:new(), 20),
io:format("Map: ~p~n", [TheMap]),
maps:fold(fun my_min/3, {undefined, undefined}, TheMap).
build(MyMap, 0) ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
my_min(Key, Value, {undefined, undefined}) ->
{Key, Value};
my_min(Key, {_,B,_}=Value, {_, {_,BB,_}}) when B < BB ->
{Key, Value};
my_min(_Key, _Value, Acc) ->
Acc.
The my_min/3 fold function has three clauses. The first matches the special start value {undefined, undefined} and returns as the new accumulator value whatever {Key, Value} it was passed. The benefit of this is not only that you avoid special processing before starting the fold, but also that if the map is empty, you'll get the special value {undefined, undefined} as the result and you can handle it accordingly. The second clause uses a guard to check if B of the value is less than the BB value in the fold accumulator, and if it is, return {Key, Value} as the new accumulator value. The final clause just returns the existing accumulator value, since this clause is called only for values greater than or equal to that in the existing accumulator.
You might also look into using a simple list of key/value tuples, since for a small number of elements it might outperform a map. If your measurements indicate you should use a list, a similar fold would work for it as well.
-module(test).
-author("andre").
%% API
-export([init/0]).
init() ->
TheMap = build(maps:new(), 24),
io:format("Map: ~p~n", [TheMap]),
List = maps:to_list(TheMap),
io:format("List: ~p~n", [List]),
Fun = fun({_, {_, V1, _}} = Element, {_, {_, V2, _}}) when V1 < V2 ->
Element;
(_, Res) ->
Res
end,
Res = lists:foldl(Fun, hd(List), tl(List)),
io:format("Res: ~p~n", [Res]).
build(MyMap, Count) when Count == 0 ->
MyMap;
build(MyMap, Count) ->
NewMap = maps:put(Count, {random:uniform(100), random:uniform(100), random:uniform(100)}, MyMap),
build(NewMap, Count - 1).
You can use maps:to_list/1 to convert the map to a list, then you can use lists:foldl/3 to calculate the minimun value.

Erlang - Searching for tuples within tuples

Using Erlang, I have the following expression:
{add,{var,a},{mul,{num,2},{var,b}}}
and I am using lists:keymember to see whether the letter b is within the expression as such:
lists:keymember(b,2,[expr])
However, it doesn't look within the third tuple '{mul,{num,2},{var,b}' as that is a separate tuple. Is there a function that will search through the whole tuple and tuples within?
Thanks
As far I as I know there are no such functions. Probably you will have to implement some custom solution using recursion. Here is my example:
-module(test).
-compile(export_all).
find(_, []) -> false;
find(E, T) when is_tuple(T) ->
find(E, tuple_to_list(T));
find(E, [H|T]) ->
case find(E, H) of
false -> find(E, T);
true -> true
end;
find(V, E) -> V == E.
And usage:
1> test:find(b, {add,{var,a},{mul,{num,2},{var,b}}}).
true
2> test:find(b, {add,{var,a},{mul,{num,2},{var,c}}}).
false
Please review your code.
Line1: this is a tree, not a list.
Line2: expr is not a variable.
What you want to do is a visitor function, and you'll have to write it yourself.
A very good start would be to read this.

Sort list of list erlang

PropertyInfo = [
[{LandNo, Acquisition, Heir, Property, LandTypeCount, LandType}],
[{LandNo, Acquisition, Heir, Property, LandTypeCount, LandType}],
[{LandNo, Acquisition, Heir, Property, LandTypeCount, LandType}],
[{LandNo, Acquisition, Heir, Property, LandTypeCount, LandType}],
]
PropertyInfo is a list of lists containing database objects in tuple, where Heir:code() will return a 6-digit code eg. "010011", "00209", ""020011".
How can I sort this list in erlang by using that Heir code?
By using lists:sort/2 and an ordering function:
manual excerpt:
sort(Fun, List1) -> List2
Types:
Fun = fun((A :: T, B :: T) -> boolean())
List1 = List2 = [T]
T => term()
Returns a list containing the sorted elements of List1,
according to the ordering function Fun. Fun(A, B) should return true
if A compares less than or equal to B in the ordering, false
otherwise.
Ordering fun could look like this:
fun([Tuple1],[Tuple2]) ->
Prop1 = element(3,Tuple1);
Prop2 = element(3,Tuple2);
case {Prop1:code(),Prop2:code()} of
{Same,Same} -> true;
{Code1,Code2} -> SomeComparisonFun(Code1,Code2)
end
end
This leaves you to provide a function that can compare those values, once you've decided on a metric that let's you say which value should be greater than some other one.
SortedList = lists:sort(
fun({_, _, A, _, _, _}, {_, _, B, _, _, _}) ->
A:code() =< B:code()
end,
PropertyInfo).
This was very simple, I used this inbuilt lists:sort() function.

Matching tuples with don't-care variables in Erlang

I am looking for a way to find tuples in a list in Erlang using a partial tuple, similarly to functors matching in Prolog. For example, I would like to following code to return true:
member({pos, _, _}, [..., {pos, 1, 2}, ...])
This code does not work right away because of the following error:
variable '_' is unbound
Is there a brief way to achieve the same effect?
For simple cases it's better to use already mentioned lists:keymember/3. But if you really need member function you can implement it yourself like this:
member(_, []) ->
false;
member(Pred, [E | List]) ->
case Pred(E) of
true ->
true;
false ->
member(Pred, List)
end.
Example:
>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]).
Use lists:keymember/3 instead.
You can do it with a macro using a list comprehension:
-define(member(A,B), length([0 || A <- B])>0).
?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]).
It is not very efficient (it runs through the whole list) but it is the closest I can think to the original syntax.
If you want to actually extract the elements that match you just remove 'length' and add a variable:
-define(filter(A,B), [_E || A =_E <- B]).
You could do it using list comprehension:
Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].
Another possibility would be to do what match specs do and use the atom '_' instead of a raw _. Then, you could write a function similar to the following:
member(X, List) when is_tuple(X), is_list(List) ->
member2(X, List).
% non-exported helper functions:
member2(_, []) ->
false;
member2(X, [H|T]) when not is_tuple(H); size(X) =/= size(H) ->
member2(X, T);
member2(X, [H|T]) ->
case is_match(tuple_to_list(X), tuple_to_list(H)) of
true -> true;
false -> member2(X, T)
end.
is_match([], []) ->
true;
is_match(['_'|T1], [_|T2]) ->
is_match(T1, T2);
is_match([H|T1], [H|T2]) ->
is_match(T1, T2);
is_match(_, _) ->
false.
Then, your call would now be:
member({pos, '_', '_'}, [..., {pos, 1, 2}, ...])
This wouldn't let you match patterns like {A, A, '_'} (checking where the first two elements are identical), but if you don't need variables this should work.
You could also extend it to use variables using a similar syntax to match specs ('$1', '$2', etc) with a bit more work -- add a third parameter to is_match with the variable bindings you've seen so far, then write function clauses for them similar to the clause for '_'.
Granted, this won't be the fastest method. With the caveat that I haven't actually measured, I expect using the pattern matching in the language using a fun will give much better performance, although it does make the call site a bit more verbose. It's a trade-off you'll have to consider.
May use ets:match:
6> ets:match(T, '$1'). % Matches every object in the table
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]]
7> ets:match(T, {'_',dog,'$1'}).
[[7],[5]]
8> ets:match(T, {'_',cow,'$1'}).
[]

Case issue in erlang

Working with Erlang's case, I'm facing a problem. The problem is the following:
other languages:
switch(A)
{
case "A" : case "B" :
//do something
break;
}
So, how to achieve the same thing using Erlang? Because sometimes it is very important to put conditions like these, to avoid overhead.
May be guards are what you want.
the_answer_is(N) when A == "A"; A == "B";
; - is OR
, - is AND
You can use case expressions in Erlang. The syntax is:
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
...
end
To quote Pragmatic Erlang:
case is evaluated as follows. First,
Expression is evaluated; assume this
evaluates to Value. Thereafter, Value
is matched in turn against Pattern1
(with the optional guard Guard1),
Pattern2, and so on, until a match is
found. As soon as a match is found,
then the corresponding expression
sequence is evaluated—the result of
evaluating the expression sequence is
the value of the case expression. If
none of the patterns match, then an
exception is raised.
An example:
filter(P, [H|T]) ->
case P(H) of
true -> [H|filter(P, T)];
false -> filter(P, T)
end;
filter(P, []) ->
[].
filter(P , L); returns a list of all those elements X in L for which P(X) is true. This can be written using pattern matching, but the case construct makes the code cleaner. Note that choosing between pattern matching and case expressions is a matter of taste, style and experience.
Not my favorite style, but you can do something like:
case A of
_ when A == "A";
A == "B" -> do_ab();
_ when A == "C";
_ when A == "D" -> do_cd();
_ -> do_default()
end.

Resources