Reputation: 1764
Going through the docs of the erlang queue here: http://erlang.org/doc/man/queue.html#member-2 I don't see a way to pull off a range of items like Enum.Take. Has anyone solved this?
Upvotes: 0
Views: 713
Reputation: 121000
Erlang is proud of using recursion wherever possible instead of imperative calls. The desired behaviour might be easily implemented:
def take(q, amount), do: do_take(q, {amount, []})
defp do_take(q, {n, acc}) when n > 0 do
case :queue.out(q) do
{{:value, e}, rest} ->
do_take(rest, {n - 1, [e | acc]})
{:empty, q} -> {acc, q}
end
end
defp do_take(q, {_, acc}), do: {acc, q}
I have not tested this code, but I believe the idea is clear.
Or, with a fancy else
syntax:
def take(q, amount), do: do_take(q, {amount, []})
defp do_take(q, {n, acc}) when n > 0 do
:queue.out(q)
else
{{:value, e}, rest} -> do_take(rest, {n - 1, [e | acc]})
{:empty, q} -> {acc, q}
end
defp do_take(q, {_, acc}), do: {acc, q}
Upvotes: 2
Reputation: 48599
I don't see a way to pull off a range of items like Enum.Take. Has anyone solved this?
Yep. From the page you linked:
split(N :: integer() >= 0, Q1 :: queue(Item)) -> {Q2 :: queue(Item), Q3 :: queue(Item)}
Splits Q1 in two. The N front items are put in Q2 and the rest in Q3.
So, you can do this:
-module(my).
-compile(export_all).
take(N, Q) ->
{Taken, _Rest} = queue:split(N, Q),
Taken.
In the shell:
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Q = queue:from_list([1,2,3,4]).
{[4],[1,2,3]}
3> T1 = my:take(1, Q).
{[],[1]}
4> queue:to_list(T1).
[1]
5> T3 = my:take(3, Q).
{[3],[1,2]}
6> queue:to_list(T3).
[1,2,3]
All operations have an amortized O(1) running time, except
filter/2
,join/2
,len/1
,member/2
,split/2
that have O(n).
Upvotes: 1