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?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With