From: Robert Klemme Date: 2007-05-25T06:27:04+09:00 Subject: Re: Enumerator for Hash 2007/5/24, Ryan Hinton : > On May 23, 12:18 pm, Robert Klemme wrote: > > You could wrap your keys in a custom class. For added convenience you > > could also wrap Hash with another class which wraps keys on insertion > > and unwraps on reading. > > ... > > > > In that case I'd probably rather do this: > > > > my_array.inject({}) {|hs, obj| hs[obj.key] ||= obj; hs }.values > > 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 -- Have a look: http://www.flickr.com/photos/fussel-foto/