Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yield within Set to eliminate in an Array

I found the following code here for eliminating duplicate records in an array:

require 'set'

class Array
  def uniq_by
    seen = Set.new
    select{ |x| seen.add?( yield( x ) ) }
  end
end

And we can use the code above as follows:

@messages = Messages.all.uniq_by { |h| h.body }

I would like to know how and what happens when the method is called. Can someone explain the internals of the code above? In the uniq_by method, we did not do anything to handle block argument. How is the passed argument handled by uniq_by method?

like image 667
pramod Avatar asked Mar 20 '23 13:03

pramod


2 Answers

Let's break it down :

seen = Set.new

Create an empty set

select{ |x| seen.add?( yield( x ) ) }

Array#select will keep elements when the block yields true.

seen.add?(yield(x)) will return true if the result of the block can be added in the set, or false if it can't.

Indeed, yield(x) will call the block passed to the uniq_by method, and pass x as an argument.

In our case, since our block is { |h| h.body }, it would be the same as calling seen.add?(x.body)

Since a set is unique, calling add? when the element already exists will return false.

So it will try to call .body on each element of the array and add it in a set, keeping elements where the adding was possible.

like image 116
Intrepidd Avatar answered Mar 23 '23 03:03

Intrepidd


The method uniq_by accepts a block argument. This allows to specify, by what criteria you wish to identify two elements as "unique".

The yield statement will evaluate the value of the given block for the element and return the value of the elements body attribute. So, if you call unique_by like above, you are stating that the attribute body of the elements has to be unique for the element to be unique.

To answer the more specific question you have: yield will call the passed block {|h| h.body} like a method, substituting h for the current x and therefore return x.body

like image 21
Alexander Presber Avatar answered Mar 23 '23 02:03

Alexander Presber