"Pit Capitain" <pit / capitain.de> schrieb im Newsbeitrag 
news:41FCBFE5.4000405 / capitain.de...
> Trans schrieb:
>> Has anyone, could anyone, write a Ruby version of this method? I'm not
>> sure what its supposed to do exaclty. Id like to see source.
>
> No problem:
>
>   require 'set'
>
>   class Array
>     def uniq_by
>       result = []
>       values = Set.new
>       each do |elem|
>         value = yield elem
>         unless values.include? value
>           values << value
>           result << elem
>         end
>       end
>       result
>     end
>   end
>
>   p ( 0 .. 9 ).to_a.uniq_by { |x| x % 4 }  # => [0, 1, 2, 3]
>
> I bet Robert will transform this into a version using inject ;-)

Since you asked...  :-))

module Enumerable
  def uniq_by
    inject({}) {|h,x| h[yield(x)] ||= x; h}.values
  end
end

>> a=(1..10).map {rand 10}
=> [2, 7, 4, 1, 9, 0, 0, 2, 5, 0]
>> a.uniq_by {|x| x%3}
=> [9, 7, 2]

Pro:
 - shorter
 - needs one less temp instace

Con:
 - not stable, original order is not maintained

A stable version:

module Enumerable
  def uniq_by
    h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x}
  end
end

>> a.uniq_by {|x| x%3}
=> [2, 7, 9]

Beautiful about this version is that it does not need the "; h" at the end 
of the inject block and no ".values", too... :-)

Kind regards

    robert