Hackerrank challenge - Dictionaries and Maps in Erlang This question is really similar to an existing one in Ruby. So the task is also the same: Day 8: Dictionaries and Maps!

The problem is that on Hackerrank my solution only passes the first and last testcases. All the other ones between them are timing out (>12s!). I tried to use map instead of dict and also read the queries first into a list and process them separately as was suggested in the discussion. I have a feeling it goes to infinite recursion because I'm doing the line read/strip wrong.

-module(solution).
-export([main/0]).

main() -&gt;
    { ok, [N]} = io:fread("", "~d"),
    Dict = read_dictionary(N, dict:new()),
    queries(Dict).

read_dictionary(0, D) -&gt; D;
read_dictionary(N, D) -&gt;
    Name = stripped_next_line(),
    Number = stripped_next_line(),
    read_dictionary(N-1, dict:store(Name, Number, D)).

queries(Dict) -&gt;
    queries(Dict, io:get_line("")).
queries(_, eof) -&gt; true;
queries(Dict, Name) -&gt;
    find_number_of(strip_line(Name), Dict),
    Next = io:get_line(""),
    queries(Dict, Next).

find_number_of(Name, Dict) -&gt;
    out(dict:find(Name, Dict), Name).

out({ok, Number}, Name) -&gt; io:format("~s=~s~n", [Name, Number]);
out(error, _) -&gt; io:format("Not found~n").

strip_line(Line) -&gt; string:strip(Line, both, $\n).
stripped_next_line() -&gt; strip_line(io:get_line("")).
There are two things you can do differently that would help:


read all the input at once, and then process it
store values such that they can be output directly, without formatting


The code below first reads all the input in chunks of 4096 characters, accumulating a list of chunks. It then reverses the list, flattens the list into a large string, and splits the entire string on newlines. After that, it converts the first element of the resulting list to an integer N, and then processes N names and numbers from the remainder of the list by storing them in a map. The value stored isn't just the phone number, but the required output string "&lt;name&gt;=&lt;number&gt;\n". Once all the entries have been processed, the rest of the input is queries, which are then processed one-by-one against the map. Query processing uses maps:get/3 with the string "Not found" used as the default for lookups that fail. This allows the return value from maps:get/3 to be unconditionally output directly to stdout.

-module(solution).
-export([main/0]).

main() -&gt;
    queries(store(read_all())).

read_all() -&gt;
    read_all([], io:get_chars("", 4096)).
read_all(In, eof) -&gt;
    [H|T] = string:tokens(lists:flatten(lists:reverse(In)), "\n"),
    {list_to_integer(H), T};
read_all(In, Data) -&gt;
    read_all([Data|In], io:get_chars("", 4096)).

store(Data) -&gt;
    store(Data, #{}).
store({0, Queries}, M) -&gt;
    {Queries, M};
store({N, [Name,Number|T]}, M) -&gt;
    store({N-1, T}, maps:put(Name, lists:flatten([Name,"=",Number,"\n"]), M)).

queries({[], _}) -&gt;
    ok;
queries({[Query|Queries], M}) -&gt;
    io:put_chars(maps:get(Query, M, "Not found\n")),
    queries({Queries, M}).


I created an input file containing 9000 entries to be stored and used it to measure this solution to be about 150 times faster than solutions that read the input line by line, as measured by running the solution on the command line in a bash shell like this:

time erl -noshell -s solution main -s init stop &lt; input


and subtracting out the overhead of starting and stopping the Erlang VM, measured like this:

time erl -noinput -s init stop


On my machine, this overhead is ~1.20s. The original solution for input with 9000 entries and 3 lookups takes ~6.25s, while the solution I've posted here runs in ~1.23s, which means it imposes hardly any overhead over that of the VM startup and shutdown.