ryanzidago

ryanzidago

Implementing a queue based on a list zipper?

Hi all,

How to implement a queue in Elixir with O(1) insertion and O(1) deletion using a list zipper?

According to this blog post on zippers, one can use a list zipper to have a queue-like behaviour:

Zipper lists are conceptually simple enough to be easy to reinvent and replace with queues.

Considering the following zipper:

defmodule Zipper.ListZipper do
  defguard is_range(range) when is_struct(range, Range)

  def new, do: {[], []}

  def from_list(list) when is_list(list), do: {[], list}

  def from_range(range) when is_range(range), do: from_list(Enum.to_list(range))

  def to_list({prev, next}), do: Enum.reverse(prev) ++ next

  def prev({[], next}), do: {[], next}
  def prev({[head | tail], next}), do: {tail, [head | next]}

  def current({_, []}), do: nil
  def current({_, [current | _]}), do: current

  def pop({_, []} = lzip), do: {nil, lzip}
  def pop({prev, [current | tail]}), do: {current, {prev, tail}}

  def next({prev, []}), do: {prev, []}
  def next({prev, [head | tail]}), do: {[head | prev], tail}

  def replace({prev, []}, val), do: {prev, [val]}
  def replace({prev, [_ | next]}, val), do: {prev, [val | next]}

  def put({prev, next}, val), do: {prev, [val | next]}

  def delete({prev, []}), do: {prev, []}
  def delete({prev, [_ | next]}), do: {prev, next}
end

If I insert the sequence 1, 2, 3 into the list zipper, the current will point to the last element 3:

iex(9)> ListZipper.new()|> ListZipper.put(1) |> ListZipper.put(2) |> ListZipper.put(3)                                          
{[], [3, 2, 1]}

Now, I could use next to move the current to the first inserted element everytime I call put/2 (unless the zipper has only one element):

iex(10)> ListZipper.new()|> ListZipper.put(1) |> ListZipper.put(2) |> ListZipper.next() |> ListZipper.put(3) |> ListZipper.next()
{[3, 2], [1]}

However, I still need to go through the whole list to get the second element 2 :think
Is it possible, or did I misunderstood the quoted sentence in the blog post?

Marked As Solved

ryanzidago

ryanzidago

Looking at the queue implementation in Elixir in rosettacode, I get the gist of it.

We use two queues, (input/output queues). When we want to pop, the input queue becomes the output queues and is reversed. Next time we want to pop, we won’t need to reverse the output queue (because it isn’t empty).

This is not always O(1) but it looks like a good compromise.

Also Liked

lud

lud

I think the Erlang queue module implements kind of the same thing. When you call :queue.new() it yelds a similar initial state: {[], []}.

Last Post!

lud

lud

I think the Erlang queue module implements kind of the same thing. When you call :queue.new() it yelds a similar initial state: {[], []}.

Where Next?

Popular in Questions Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130579 1222
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New