I have a tuple as {'Europe-Fiat-Italy-Warehouse'}.
Car = {'Europe-Fiat-Italy-Warehouse'}.
I want to search the string "Fiat" in the above tuple without converting them to string tokens in a list.
i.e.,
(madmax#erlang)46>string:tokens(atom_to_list(element(1, Car)), "-").
["Europe","Fiat","Italy","Warehouse"]
(madmax#erlang)46> ["Europe", "Fiat" | Other] =
string:tokens(atom_to_list(element(1, Car)), "-").
["Europe","Fiat","Italy","Warehouse"]
(madmax#erlang)47>
(madmax#erlang)47> Other.
["Italy","Warehouse"]
(madmax#erlang)48>
As in above, we convert tuple to atom, then atom to list and then list to string tokens. Is there any optimized way? or any Buit-in-Function available in erlang which make this task easier?
Use string:str
check documentation here: http://erlang.org/doc/man/string.html#str-2
it will return position of substring, zero if substring is not found.
string:str(atom_to_list(element(1, Car)), "Fiat")
the representation of atoms in memory is not using strings (or list), to search in an atom name there is no other choice than convert it into list first. It is possible to use library function such as string:str/2, but you may have bad results since string you search could be part of a longer one, so you should keep the call to string:token/2, then it depends of what you want to do:
1> Car = {'Europe-Fiat-Italy-Warehouse'}.
{'Europe-Fiat-Italy-Warehouse'}
2> Words = string:tokens(atom_to_list(element(1, Car)), "-").
["Europe","Fiat","Italy","Warehouse"]
3> lists:member("Fiat",Words). % only a test
true
4> lists:dropwhile(fun(X) -> "Fiat" =/= X end ,Words). % words after
["Fiat","Italy","Warehouse"]
5> lists:takewhile(fun(X) -> "Fiat" =/= X end ,Words). % words before
["Europe"]
6> lists:member("Fit",Words). % same thing with a bad match
false
7> lists:dropwhile(fun(X) -> "Fit" =/= X end ,Words).
[]
8> lists:takewhile(fun(X) -> "Fit" =/= X end ,Words).
["Europe","Fiat","Italy","Warehouse"]
9>
F# makes it easy to unpack tuples. Unpacking lists is also feasible, but the compiler issues a warning:
let m = [1; 2; 3]
let [a; b; c] = m
// Incomplete pattern matches on this expression. For example, the value '[_;_;_;_]' may indicate a case not covered by the pattern(s)
Is there a way to avoid this warning?
You can disable warnings per file by using the #nowarn directive (in your case #nowarn "25") or you can disable warnings on the command line with --nowarn.
Check out the F# Compiler Directives for details.
There is currently no way to re-enable warnings again, when first disabled.
Your match may (unexpectedly) result in a runtime error if the number of elements cannot be unpacked to [a;b;c], so instead you can use a complete match that is explicit about the risc:
let m = [1;2;3]
let (a,b,c) =
match m with
| [a;b;c] -> (a,b,c)
| _ -> failwith "Expected exactly three items in m"
What would happen if your list m has 2 or 4 elements?
There is obviously a way, plain old pattern matching:
let a, b, c =
match m with
| [a;b;c] -> a,b,c
| _ -> ... // handle the length!=3 case
F# allows you to deconstruct the right-hand side objects that way when there's clear that you only have a single case you need to cover. This is the case with tuples, since there's only one tuple type that would match both the left and the right hand side. Something like this obviously would not compile, because the types won't match:
let m = 1, 2
let a, b, c = m
Yet in your case there's no guarantee that you're not in fact in this scenario:
let m = [ 1; 2 ]
let [1;2;3] = m
You're in fact asking the compiler to allow non-exhaustive pattern matching. You can disable the warning as noted in the other answer, but you're inviting runtime errors that way.
One obvious, but hardly elegant, way is:
let m = [1; 2; 3]
let a = List.item 0 m
let b = List.item 1 m
let c = List.item 2 m
You can write a helper function to make it neater:
let unpack3 x = (List.item 0 x, List.item 1 x, List.item 2 x)
let (a, b, c) = unpack3 m
Basically a list is not a great fit if you know you are always going to have a fixed number of items.
I am trying to learn Erlang and had gotten no further than operators when I ran into a problem:
5> TheList = [2,4,6,8].
[2,4,6,8]
6>
6> [N || N <- TheList, N rem 3 =:= 0].
[6]
7>
7> TheList.
[2,4,6,8]
8>
8> [2*N || N <- TheList, N rem 3 =:= 0].
"\f"
9>
Why do I get "\f" in the last operation? Shouldn't it be [12]? What does "\f" mean? Thanks.
It is explained here for example:
Erlang has no separate string type. Strings are usually represented by lists of integers (and the string module of the standard library manipulates such lists). Each integer represents the ASCII (or other character set encoding) value of the character in the string. For convenience, a string of characters enclosed in double quotes (") is equivalent to a list of the numerical values of those characters.
You can use io:format functions:
1> io:format("~w~n", [[2*N || N <- [2,4,6,8], N rem 3 =:= 0]]).
[12]
or disble this behaviour with shell:strings/1 function starting with Erlang R16B:
2> shell:strings(false).
true
3> [2*N || N <- [2,4,6,8], N rem 3 =:= 0].
[12]
As #Atomic_alarm has mentioned in the comment, it is due to erlang printing out the answer using string syntax rather than the list of integer. The default value is true, where as to see [12], you want the value set as false. The documentation for it is here.
What is the most correct (and fastest) way in Erlang to split the given list into sublists depending on the element position? E.g. I want to get the sublist of every Nth elements from list: [1,2,3,14,5,16,7,8] to [1,14,7], [2,5,8], [3,16]? The N could have any reasonable value.
Do you really need the fastest way? Every time I start implementation with easiest (most naive) way. And only when I realize that it is performance bottleneck, I start optimize it.
So, most naive way:
split(List, ByElem) ->
do_split(List, lists:duplicate(ByElem, []), []).
do_split([], RestGroups, Acc) ->
Groups = lists:reverse(Acc) ++ RestGroups,
[ lists:reverse(G) || G <- Groups ];
do_split([Elem | Rest], [Group | RestGroups], Acc) ->
do_split(Rest, RestGroups, [[Elem | Group] | Acc]);
do_split(List, [], Acc) ->
do_split(List, lists:reverse(Acc), []).
Actually, I believe there is nothing to do with performance of this code, and I don't see any ways to dramatically improve it.
There is no function to filter on position in a list, so you have to use split:
1> Sp = fun Sp(L,N,R) when length(L) =< N -> lists:reverse([L|R]);
1> Sp(L,N,R) -> {L1,L2} = lists:split(N,L), Sp(L2,N,[L1|R]) end.
#Fun<erl_eval.42.90072148>
2> Split= fun (L,N) when is_list(L), is_integer(N), N > 0 -> Sp(L,N,[]) end.
#Fun<erl_eval.12.90072148>
3> Split([1,2,3,4,5,6,7,8],3).
[[1,2,3],[4,5,6],[7,8]]
4>
[edit] Ooops, it doesn't answer the question. If you don't mind the order of sublist, another solution maybe
1> L = [1,2,3,4,5,6,7,8].
[1,2,3,4,5,6,7,8]
2> N = 3.
3
3> [lists:reverse(Y) || Y <- lists:foldl(fun(X,[H|T]) -> T++[[X|H]] end , lists:duplicate(N,[]),L)].
[[3,6],[1,4,7],[2,5,8]]
4>
the next version restore the order:
1> F = fun(List,Chunk) -> {Si,L1} = lists:foldl(fun(X,{S,[H|T]}) -> {S+1,T++[[X|H]]} end , {0,lists:duplicate(Chunk,[])},List),
1> {L2,L3} = lists:split(Chunk - Si rem Chunk,L1),
1> [lists:reverse(Y) || Y <- L3 ++ L2] end.
#Fun<erl_eval.12.90072148>
2> F(lists:seq(1,130),11).
[[1,12,23,34,45,56,67,78,89,100,111,122],
[2,13,24,35,46,57,68,79,90,101,112,123],
[3,14,25,36,47,58,69,80,91,102,113,124],
[4,15,26,37,48,59,70,81,92,103,114,125],
[5,16,27,38,49,60,71,82,93,104,115,126],
[6,17,28,39,50,61,72,83,94,105,116,127],
[7,18,29,40,51,62,73,84,95,106,117,128],
[8,19,30,41,52,63,74,85,96,107,118,129],
[9,20,31,42,53,64,75,86,97,108,119,130],
[10,21,32,43,54,65,76,87,98,109,120],
[11,22,33,44,55,66,77,88,99,110,121]]
3>
I'm trying to create an if..else if condition in Erlang within a receive..end. statement in order to pass two variables A and B so that they can be tested for equivalence.
In the shell I tried typing:
6> Pid = spawn(ifelse,receiving,[]).
** exception error: no match of right hand side value <0.54.0>
7>
What I wanted was to use Pid ! {self(), 1,2}. and Pid ! {self(), 2,2}. to test both cases but something is wrong.
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid,A,B}->
if
A =:= B ->
io:format(" B equals A ~n"),
Pid ! "True";
A =/= B ->
io:format(" B does not equal A ~n"),
Pid ! "False";
true -> {error, wrong_value}
end
end.
By the way if I have receiving(A,B) instead with two variables how would I spawn that similarly to Pid = spawn(ifelse,receiving,[]).? I tried using Pid = spawn(ifelse,receiving(1,2),[]). but that gave an error.
As #rvirding commented, Erlang is single assignement. Your problem is probably related to the fact that you have already bound a value to variable Pid and therefore you can't bind any new value to it.
Only in a shell (not recommended in real code) can you unbind a single variable using f(Variable):
1> A = 4.
4
2> f(A).
ok
3> A = 5.
5
or unbind all the variables using f()
Notice that this is only for testing purposes.
As far as I can see your code is right, even though I suggest you to use case and pattern matching instead of an if statement.
So I would rewrite your code as follows:
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid, A, B} ->
case A =:= B of
true ->
Pid ! "True";
false ->
Pid ! "False"
end
end.
You can test it as follows:
1> Pid = spawn(ifelse,receiving,[]).
<0.34.0>
2> ShellPid = self().
<0.32.0>
3> Pid ! {ShellPid, 4, 5}.
{0.32.0, 4, 5}
4> flush().
Shell got "False"
Another thing is that I don't see why you should use a string value for "True" and "False" since you could actually use atoms. Moreover your code can work only once because after the if-else or case the process just dies. You can tackle this issue by using a recursive function.
Here is a module with both the modifications:
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid, A, B} ->
Pid ! A =:= B
end,
receiving().
and here is how to test it (in a new shell so you don't have to use f() ):
1> Pid = spawn(ifelse,receiving,[]).
<0.34.0>
2> ShellPid = self().
<0.32.0>
3> Pid ! {ShellPid, 4, 5}.
{0.32.0, 4, 5}
4> flush().
Shell got false
5> Pid ! {ShellPid, 4, 4}.
{0.32.0, 4, 4}
6> flush().
Shell got true
If you have define a function receiving/2 in your file, that means you have something like :
-module(ifelse).
-export([receiving/0,receiving/2]).
receiving() ->
some_code.
receiving(A,B) ->
other_code.
you may call it with
Pid = spawn(ifelse,receiving,[1,2]).
By the way, it is not usual to write if statements in erlang, The reason is that if one case doesn't match any condition, the code will crash.
5> F=fun(X) -> if (X rem 2) == 0 -> X+1 end end.
#Fun<erl_eval.6.82930912>
6> F(4).
5
7> F(5).
** exception error: no true branch found when evaluating an if expression
8>
If you want to avoid this, you have to have a default guard (and then it looks like a case).
8> F1=fun(X) -> if (X rem 2) == 0 -> X+1;
8> true -> X end end.
#Fun<erl_eval.6.82930912>
9> F1(4).
5
10> F1(5).
11>
The usual way to code your function is more like this:
receiving() ->
receive
{Pid,_A,_A} when is_pid(Pid) ->
% use the pattern matching to verify that the 2 elements are equal
% and a guard test to check that the first element is a pid.
% Note that in this case it is a strict equals. I use _A because the code doesn't
% care of the value itself
io:format(" B equals A ~n"),
Pid ! "True";
{Pid,_,_} when is_pid(Pid) ->
% use pattern maching to verify the that message is a tupple of 3 elements
% and a guard test to check that the first element is a pid.
% For the 2 last elements I use _, so the data is not bound to any variable,
% only the structure is tested
io:format(" B does not equal A ~n"),
Pid ! "False";
_ -> {error, wrong_value}
end.
I tested this in the shell:
14> F = fun() ->
14> receive
14> {Pid,_A,_A} when is_pid(Pid) ->
14> io:format(" B equals A ~n"),
14> Pid ! "True";
14> {Pid,_,_} when is_pid(Pid) ->
14> io:format(" B does not equal A ~n"),
14> Pid ! "False";
14> _ -> {error, wrong_value}
14> end
14> end.
#Fun<erl_eval.20.82930912>
15> Pid = spawn(F).
<0.58.0>
16> Pid ! {self(),1,2}.
B does not equal A
{<0.51.0>,1,2}
17> % the returm value of "proc ! Mess" is Mess. It is what we get on the console on previous line
17> flush(). % use flush() to get the messages received by the shell
Shell got "False"
ok
18> Pid ! {self(),test,test}. % the process Pid is terminated now. when we send a message to it,
18> % it is simply "lost".
{<0.51.0>,test,test}
19> % it is necessary though to use a new variable Pid1 and spawn a new process
19> % (see rvirding message and user601836 answer)
19> Pid1 = spawn(F).
<0.63.0>
20> Pid1 ! {self(),test,test}.
B equals A
{<0.51.0>,test,test}
21> flush().
Shell got "True"
ok
22> Pid2 = spawn(F).
<0.68.0>
23> Pid2 ! {hello,test,test}.
{hello,test,test}
24> flush().
ok
25> % of course there is no message sent back, no io:format to print something on the console,
25> % the returned value of the function in the error case is "lost".
25> % if you want to have a permanent process you must have a recursive loop,
25> % calling receiving() were needed.