2007/5/24, Ryan H. [email protected]:
Now I remember why I wanted my earlier approach. My object has
several Array member variables. By default, my #hash and #eql?
methods use all of them. In one case I need to ignore 2 of the 4
arrays, e.g. for a uniqueness hash. I can use your second method
thus.
my_array.inject({}) {|hs, obj| hs[obj.arr1 + obj.arr2] ||= obj;
hs }.values
Appending is not safe:
[1,2] + [3,4,5] → [1,2,3,4,5]
[1,2,3] + [4,5] → [1,2,3,4,5]
You want to be creating new arrays with two elements:
my_array.inject({}) {|hs, obj| hs[[obj.arr1, obj.arr2]] ||= obj; hs
}.values
But won’t this create a bevy of new Array objects with the “+” method
(two for each item in the original array)?
Yes, but I’d rather first try the suggestion above out before starting
to think about optimizations.
I could instead pre-hash
the values something like the following.
my_array.inject({}) {|hs, obj| hs[obj.arr1.hash ^ obj.arr2.hash] ||=
obj; hs }.values
That’s a bad idea because of the nature of hash values, as you
correctly identified:
This avoids the new Array spew, but I will lose unique objects if my
fabricated hash keys clash (i.e. same hash key for unique arrays). If
I can specify different methods to use in place of #hash and #eql?, I
can get the same behavior without the performance penalty. (My code
is already slow.)
I think I’ll use your wrapping Hash idea. Thanks!
I’d start with the other approach which is considerably easier.
robert