Here Map is a map data consisting of the key and value pairs like
Map = # {"a" => "Apple","b" =>"bat","c" =>"cat ",
"d" => "dog","e" => "eagle","f" => "fan ","g" => "goat",
"h" =>"hat","i" =>"ink","j" =>"jar","k" =>"king","l" =>"lion ",
"m" =>"madam","n" =>"nike","o" => "orange","p" =>"pot",
"q" =>"queue ","r" =>"rat","s" =>"snake","t" =>"tea ",
"u" =>"umbrella","v" =>"van ","w" =>"wolf ","x" =>"xperia ",
"y" =>"yawk","z" =>"zoo "}
I am trying to to print the following below:
Example:
Input: Apple nike goat lion eagle
Expected output: Angle.
Tried code:
-module(main).
-export([start/1,func/2]).
start(Str) ->
Map = # {"a" => "Apple","b" =>"bat","c" =>"cat ","d" => "dog","e" => "eagle","f" => "fan ","g" => "goat","h" =>"hat","i" =>"ink","j" =>"jar","k" =>"king","l" =>"lion ","m" =>"madam","n" =>"nike","o" => "orange","p" =>"pot","q" =>"queue ","r" =>"rat","s" =>"snake","t" =>"tea ","u" =>"umbrella","v" =>"van ","w" =>"wolf ","x" =>"xperia ","y" =>"yawk","z" =>"zoo "},
Chunks = string:tokens(Str, [$\s]),
io:format("~n~p",[Chunks]),
L = func(Chunks,Map),
io:format("~p",[L]).
func([],#{}) ->
io:format("~nCompleted~n");
func([First | Rest], Map) ->
Fun = fun(K, V, Acc) ->
if V == First -> [K | Acc];
true -> Acc
end
end,
maps:fold(Fun, [], Map),
func(Rest, Map).
Anyone please suggest me on this?
You say your input is:
Apple nike goat lion eagle
but that isn't an erlang term, so your input is nonsensical.
If your input is actually the string "Apple nike goat lion eagle", then I'm not sure why you need your map because you can just extract the first letter of each word:
-module(a).
-compile(export_all).
get_first_letters_of_words(Sentence) ->
Words = string:split(Sentence, "\s", all),
Result = get_first_letters(Words, _Acc=[]),
io:format("~p~n", [Result]).
get_first_letters([ [Int|_Ints] | Words], Acc) ->
get_first_letters(Words, [Int|Acc]);
get_first_letters([], Acc) ->
lists:reverse(Acc).
In the shell:
63> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
64> a:get_first_letters_of_words("Apple nike goat lion eagle").
"Angle"
ok
You can read about how to work with strings below. The list of words returned by string:split/3 is actually a list where each element is a list of integers, e.g.
[ [97,98,99], [100,101,102] ]
The function get_first_letters/2 might be easier to understand if you write it like this:
get_first_letters([Word|Words], Acc) ->
[Int|_Ints] = Word,
get_first_letters(Words, [Int|Acc]);
get_first_letters([], Acc) ->
lists:reverse(Acc).
It also makes no sense to create a map where the words are the values and the first letters are the keys. Instead, you would create a map where the words are the keys and the values are the first letters, then you could call maps:get/2 with a word to look up the first letter.
If you actually have a map where a word/value is associated with more than one key, then things are a little trickier. The following example retrieves all the keys associated with a word:
-module(a).
-compile(export_all).
get_code_for_words(Sentence) ->
Words = string:split(Sentence, "\s", all),
LettersWords = # {"a" => "Apple",
"b" => "bat",
"c" => "cat",
"x" => "bat"},
Result = get_codes(Words, LettersWords, _AllCodes=[]),
io:format("~p~n", [Result]).
get_codes([Word|Words], Map, AllCodes) ->
NewAllCodes = maps:fold(fun([K],V,Acc) ->
case V =:= Word of
true -> [K|Acc];
_ -> Acc
end
end,
AllCodes,
Map),
get_codes(Words, Map, NewAllCodes);
get_codes([], _Map, AllCodes) ->
lists:reverse(AllCodes).
In the shell:
79> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
80> a:get_code_for_words("Apple bat cat").
"abxc"
ok
In erlang, a string is just a shortcut for creating a list of integers, where the integers in the list are the ascii codes of the characters in the string.
8> "abc" =:= [97, 98, 99].
true
You may not like that, but that's the way it is: a double quoted string tells erlang to create a list of integers. The shell is misleading because sometimes the shell prints out the string "abc" as "abc" instead of [97, 98, 99]. To prevent the shell from misleading you, you can execute shell:strings(false) in the shell, and then the shell will always output lists of integers for strings:
12> shell:strings(false).
true
13> "abc".
[97,98,99]
That will continue for the rest of your shell session (or until you execute shell:strings(true). You can still explicitly tell the shell to print a string if you want:
16> io:format("~p~n", ["abc"]).
"abc"
ok
When you use [Head|Tail] to match a list of integers, e.g. a double quoted string, Head will match an integer:
9> [Head|Tail] = "abc".
"abc"
10> Head.
97
The problem is that the keys in your map are strings--not integers. The easiest way to handle that is to turn the integer into a string by inserting it into a list:
11> [Head].
"a"
Here is an example:
-module(a).
-compile(export_all).
get_words(ListOfInts) -> %% ListOfInts can be a double quoted string
LettersWords = # {"a" => "Apple",
"b" => "bat",
"c" => "cat",
"d" => "dog"},
Words = get_words(ListOfInts, LettersWords, _Acc=[]),
io:format("~p~n", [Words]).
get_words([Int|Ints], Map, Acc) ->
Letter = [Int],
Word = maps:get(Letter, Map),
get_words(Ints, Map, [Word|Acc]);
get_words([], _Map, Acc) -> Acc.
In the shell:
3> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
4> a:start("cad").
["dog","Apple","cat "]
ok
If you would like the results in the same order as the letters in your input string, then return lists:reverse(Acc) instead of Acc.
If you want to display each word--not a list of words, like this:
"cat" "Apple" "dog"
you can do this:
show_results(Words) ->
lists:foreach(fun(Word) -> io:format("~p ", [Word]) end,
Words),
io:format("~n").
If you don't want to display the quotes, for instance:
cat Apple dog
you can use the ~s control sequence:
show_results(Words) ->
lists:foreach(fun(Word) -> io:format("~s ", [Word]) end,
Words),
io:format("~n").
I propose you this. Of course to be efficient you should store the reverse dictionary somewhere, in a server state for example.
1> % Enter the dictionary
1> Map = # {"a" => "apple","b" =>"bat","c" =>"cat","d" => "dog","e" => "eagle","f" => "fan","g" => "goat","h" =>"hat","i" =>"ink","j" =>"jar","k" =>"king","l" =>"lion","m" =>"madam","n" =>"nike","o" => "orange","p" =>"pot","q" =>"queue","r" =>"rat","s" =>"snake","t" =>"tea","u" =>"umbrella","v" =>"van","w" =>"wolf","x" =>"xperia","y" =>"yawk","z" =>"zoo"}.
#{"a" => "apple","b" => "bat","c" => "cat","d" => "dog",
"e" => "eagle","f" => "fan","g" => "goat","h" => "hat",
"i" => "ink","j" => "jar","k" => "king","l" => "lion",
"m" => "madam","n" => "nike","o" => "orange","p" => "pot",
"q" => "queue","r" => "rat","s" => "snake","t" => "tea",
"u" => "umbrella","v" => "van","w" => "wolf",
"x" => "xperia","y" => "yawk","z" => "zoo"}
2> % You have a dictionary letters to things while you need a dictionary things to letters. Let's revert it
2> L = maps:to_list(Map). % First trasform into list
[{"a","apple"},
{"b","bat"},
{"c","cat"},
{"d","dog"},
{"e","eagle"},
{"f","fan"},
{"g","goat"},
{"h","hat"},
{"i","ink"},
{"j","jar"},
{"k","king"},
{"l","lion"},
{"m","madam"},
{"n","nike"},
{"o","orange"},
{"p","pot"},
{"q","queue"},
{"r","rat"},
{"s","snake"},
{"t","tea"},
{"u","umbrella"},
{"v","van"},
{"w","wolf"},
{"x","xperia"},
{"y","yawk"},
{"z","zoo"}]
3> IL = [{V,K} || {K,V} <- L]. % exchange Key and Values
[{"apple","a"},
{"bat","b"},
{"cat","c"},
{"dog","d"},
{"eagle","e"},
{"fan","f"},
{"goat","g"},
{"hat","h"},
{"ink","i"},
{"jar","j"},
{"king","k"},
{"lion","l"},
{"madam","m"},
{"nike","n"},
{"orange","o"},
{"pot","p"},
{"queue","q"},
{"rat","r"},
{"snake","s"},
{"tea","t"},
{"umbrella","u"},
{"van","v"},
{"wolf","w"},
{"xperia","x"},
{"yawk","y"},
{"zoo","z"}]
4> IM = maps:from_list(IL). % build the expected dictionary
#{"apple" => "a","bat" => "b","cat" => "c","dog" => "d",
"eagle" => "e","fan" => "f","goat" => "g","hat" => "h",
"ink" => "i","jar" => "j","king" => "k","lion" => "l",
"madam" => "m","nike" => "n","orange" => "o","pot" => "p",
"queue" => "q","rat" => "r","snake" => "s","tea" => "t",
"umbrella" => "u","van" => "v","wolf" => "w",
"xperia" => "x","yawk" => "y","zoo" => "z"}
5> Input = ["apple", "nike", "goat", "lion", "eagle"]. % define a test input
["apple","nike","goat","lion","eagle"]
6> lists:reverse(lists:foldl(fun(X,Acc) -> [V] = maps:get(X,IM), [V|Acc] end, [], Input)). % translate
"angle"
7>
I want to get the room's name or subject from one of the ejabberd hooks.
I've a method like in the below code and I want to get room's name or subject within that method.
Is something like that possible?
muc_filter_message(Stanza, MUCState, RoomJID, FromJID, FromNick) ->
PostUrl = gen_mod:get_module_opt(FromJID#jid.lserver, ?MODULE, post_url, fun(S) -> iolist_to_binary(S) end, list_to_binary("")),
Token = gen_mod:get_module_opt(FromJID#jid.lserver, ?MODULE, auth_token, fun(S) -> iolist_to_binary(S) end, list_to_binary("")),
Body = fxml:get_path_s(Stanza, [{elem, list_to_binary("body")}, cdata]),
_LISTUSERS = lists:map(
fun({_LJID, Info}) ->
binary_to_list(Info#user.jid#jid.luser) ++ ".."
end,
dict:to_list(MUCState#state.users)
),
?DEBUG(" ######### GROUPCHAT _LISTUSERS = ~p~n ####### ", [_LISTUSERS]),
_AFILLIATIONS = lists:map(
fun({{Uname, _Domain, _Res}, _Stuff}) ->
binary_to_list(Uname) ++ ".."
end,
dict:to_list(MUCState#state.affiliations)
),
?DEBUG(" ######### GROUPCHAT _AFILLIATIONS = ~p~n ####### ", [_AFILLIATIONS]),
_OFFLINE = lists:subtract(_AFILLIATIONS, _LISTUSERS),
?DEBUG(" ######### GROUPCHAT _OFFLINE = ~p~n ####### ", [_OFFLINE]),
if
Stanza /= "", length(_OFFLINE) > 0 ->
Sep = "&",
Post = [
"type=groupchat", Sep,
"to=", RoomJID#jid.luser, Sep,
"from=", FromJID#jid.luser, Sep,
"offline=", _OFFLINE, Sep,
"nick=", FromNick, Sep,
"body=", url_encode(binary_to_list(Body)), Sep,
"access_token=", Token
],
?INFO_MSG("Sending post request to ~s with body \"~s\"", [PostUrl, Post]),
httpc:request(post, {binary_to_list(PostUrl), [], "application/x-www-form-urlencoded", list_to_binary(Post)},[],[]),
Stanza;
true ->
Stanza
end.
Thanks