Priority Queue implementation for top k frequent elements leetcode in Ruby While working on the following leetcode problem: https://leetcode.com/problems/top-k-frequent-elements/ I used a Priority Queu implementation in Ruby. I have learned how to implement a Priority Queu in Java in  Robert Sedgewick's Algorithms book. When inserting Hashes into the Priority Queue for example { 1 =&gt; 3} this made me refactored the Priotity's Queue in such a way so I was able to compare two hashes values.
The implementation is much straight forward when your dealing with numbers and characters but it made me wonder what would be the best implementation with using objects or hashes.
def top_k_frequent(nums, k)
  ans = []
  h = Hash.new(0)

  nums.each do |num|
    h[num] += 1
  end

  heap = Heap.new
  h.each do |k,v|
    heap.insert({k =&gt; v})
  end

  k.times do
    a = heap.del_max
    ans.push(a.keys[0])
  end

  ans
end


class Heap
  def initialize
    @n = 0
    @pq = []
  end

  def insert(v)
    @pq[@n += 1] = v
    swim(@n)
  end

  def swim(k)
    while k &gt; 1 &amp;&amp; less((k / 2).floor, k)
      swap((k / 2).floor, k)
      k = k/2
    end
  end

  def swap(i, j)
    temp = @pq[i]
    @pq[i] = @pq[j]
    @pq[j] = temp
  end

  def less(i, j)
    @pq[i].values[0] &lt; @pq[j].values[0]
  end

  def del_max
    max = @pq[1]
    swap(1, @n)
    @n -= 1
    @pq[@n + 1] = nil
    sink(1)
    max
  end

  def sink(k)
    while 2 * k &lt;= @n
      j = 2 * k

      if !@pq[j + 1].nil?
        j += 1 if j &gt; 1 &amp;&amp; @pq[j].values[0] &lt; @pq[j + 1].values[0]
      end
      break if !less(k, j)

      swap(k, j)
      k = j
    end
  end
end

There are a few things that come to mind that I wish to probably learn. Keep in mind that I would like to prepare for algorithm interviews and so I would like to avoid as much synthetic sugar as possible.

@pq[j].values[0] check for example how to get to a hash values I need to use values[0] is there a better way for this?
There are 3 loops in the top_k_frequent method. How would yo go about optimizing this implementation?
a.keys[0] notice how I get the key of the element in Ruby is there a cleaner way of doing this?

This brought to my attention that in case of dealing with more complex objects the Priority Queue's API might be needed to refactored to be able to compare between objects, what would be the best way of dealing with that? Would creating another class which you pass to the Priority Queue would be a better solution?
Here is the implementation I have for Priority Queue's prior to editing to deal with hashes.
class Heap
  attr_accessor :pq, :n

  def initialize
    @pq = [] # heap order complete binary tree
    @n = 0 # in pq[1..N] with pq[0] unused
  end

  def empty?
    @n == 0
  end

  def size
    @n
  end

  def insert(v)
    @pq[@n += 1] = v
    swim(@n) # position in heap
  end

  # trickleup
  def swim(k)
    while k &gt; 1 &amp;&amp; less((k / 2).floor, k) # parent: k/2 parent less than child?
      swap((k/2).floor, k)
      k = k / 2
    end
  end

  def del_max
    max = @pq[1]  # Retrieve max key from top.
    swap(1, @n) # Exchange with last item.
    @n -= 1
    @pq[@n + 1] = nil # Avoid loitering. max added to end on swap make nil
    sink(1) # Restore HEAP property
    max
  end

  # Trickledown
  def sink(k)
    while 2 * k &lt;= @n
      j = 2 * k # child

      if !@pq[j + 1].nil? # check if there is a right child
        j += 1 if j &gt; 1 &amp;&amp; @pq[j] &lt; @pq[j + 1] # if left child less than right child
      end
      break if @pq[k] &gt; @pq[j] # If parent greater than child break

      swap(k, j)
      k = j
    end
  end

  def less(i, j)
    @pq[i] &lt; @pq[j]
  end

  def swap(i, j)
    temp = @pq[i]
    @pq[i] = @pq[j]
    @pq[j] = temp
  end
end
The objects in the priority queue (as implemented above) have their priority determined by &lt;, &gt;, and ==. So however equality is defined for the object determines its priority. For numbers and strings, this is fairly obvious but the default implementation of equality, less than and greater than for hashes may surprise you and not give the result you are expecting.
Perhaps you could consider passing in a block to your initialize method to allow you to provide your own comparison function in those cases where the default one doesn't match your needs. Like Enumerable::sort does.