Hamming numbers are numbers of the form  

    H = 2i × 3j × 5k
           where 
     i,  j,  k  ≥  0 

Hamming numbers   are also known as   ugly numbers   and also   5-smooth numbers   (numbers whose prime divisors are less or equal to 5).



Task

Generate the sequence of Hamming numbers, in increasing order.   In particular:

 Show the   first twenty   Hamming numbers.
 Show the   1691st   Hamming number (the last one below   231).
 Show the   one millionth   Hamming number (if the language – or a convenient library – supports arbitrary-precision integers).


Related tasks

 Humble numbers
 N-smooth numbers


References

 Wikipedia entry:   Hamming numbers     (this link is re-directed to   Regular number).
 Wikipedia entry:   Smooth number
 OEIS entry:   A051037   5-smooth   or   Hamming numbers
 Hamming problem from Dr. Dobb's CodeTalk (dead link as of Sep 2011; parts of the thread here and here).


defmodule Hamming do
  def generater do
    queues = [{2, queue}, {3, queue}, {5, queue}]
    Stream.unfold({1, queues}, fn {n, q} -> next(n, q) end)
  end
 
  defp next(n, queues) do
    queues = Enum.map(queues, fn {m, queue} -> {m, push(queue, m*n)} end)
    min    = Enum.map(queues, fn {_, queue} -> top(queue) end) |> Enum.min
    queues = Enum.map(queues, fn {m, queue} ->
               {m, (if min==top(queue), do: erase_top(queue), else: queue)}
             end)
    {n, {min, queues}}
  end
 
  defp queue, do: {[], []}
 
  defp push({input, output}, term), do: {[term | input], output}
 
  defp top({input, []}), do: List.last(input)
  defp top({_, [h|_]}), do: h
 
  defp erase_top({input, []}), do: erase_top({[], Enum.reverse(input)})
  defp erase_top({input, [_|t]}), do: {input, t}
end
 
IO.puts "first twenty Hamming numbers:"
IO.inspect Hamming.generater |> Enum.take(20)
IO.puts "1691st Hamming number:"
IO.puts Hamming.generater |> Enum.take(1691) |> List.last
IO.puts "one millionth Hamming number:"
IO.puts Hamming.generater |> Enum.take(1_000_000) |> List.last