"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...
"Florian Gross" <flgr@ccan.de> schrieb im Newsbeitrag news:36482aF4tni5tU1@individual.net...
Pit Capitain wrote:
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
module Enumerable
def uniq_by()
inject() do |state, item|
value = yield(item)
state.include?(value) ? state : state + [item]
end
end
end
Hmmm... When deciding whether to include an element or not you mix values and converted values. That's not the same as what the implementation above does.
Also (as optimization) you could use "state << item" instead of "state + [item]" because Array#<< returns self. This saves you a lot temporary 1element arrays and avoids creating new arrays all the time (Array#+ creates a new Array).
Also (as optimization) you could use "state << item" instead of "state + [item]" because Array#<< returns self. This saves you a lot temporary 1element arrays and avoids creating new arrays all the time (Array#+ creates a new Array).
I dislike having the block of .inject having side effects. That sort of defeats the purpose IMHO.
Also (as optimization) you could use "state << item" instead of "state + [item]" because Array#<< returns self. This saves you a lot temporary 1element arrays and avoids creating new arrays all the time (Array#+ creates a new Array).
I dislike having the block of .inject having side effects. That sort of defeats the purpose IMHO.
I don't think it's a side effect, since it's just injecting something
into the accumulator or "injectee". This might be exactly what you
want if, for example, you have multiple references to the accumulator:
x =
y = x
["a","b","c"].inject(x) {|m,n| m << n.upcase}
puts y # ["A", "B", "C"]
Otherwise in a case like this you could just use #map.