Robert Klemme
8/9/2007 11:43:00 AM
2007/8/9, Milo Thurston <knirirr@gmail.com>:
> Robert Klemme wrote:
> > selection = things.select {|x| x.name = "foo"}
>
> That is closer, but still not quite it.
> A slight change of my previously posted code may make it clearer. In
> this case I start with an array of "Thing" objects called "things", and
> would like an array called "uniquely_named_things" containing Things
> where the name is unique.
>
>
> check = Hash.new
> uniquely_named_things = Array.new
> things.each do |s|
> if check[s.name].nil?
> uniquely_named_things << s
> end
> check[s.name] = 1
> end
Your code seems to implement something different from your wording.
Your wording says "keep only things whose name is not used by another
thing". Your code does "keep one thing per unique name".
> Basically, I wonder if anything that does the same as this has already
> been included in Ruby.
There are numerous ways to achieve that. As I am a big fan of #inject,
this is probably my first choice:
# 1. keep only one thing per name
selection = things.inject({}) {|h,th| h[th.name] ||= th; h}.values
# 2. keep things whose name is unique
selection = things.
inject(Hash.new {|h,k| h[k]=[]}) {|h,th| h[th.name] << th; h}.
select {|k,v| v.size == 1}.
map {|k,v| v}
# 2. alternative impl.
selection.things.
inject({}) do |h,th|
h[th.name] = h.has_key? th.name ? nil : th
h
end.values.compact
If I am not mistaken David's code implements the second solution
similar to my alternative implementation.
Kind regards
robert