> Markus wrote: > > My guess is that either++ 1) you will find in answering these questions > that you are really wanting a simple combination of two standard > collections, or 2) you will get tangled in trying to come up with > something consistent, or 3) I will learn something interesting. > > > Hal wrote: > > I fear 1 or 2, but I hope for 3. ;) Here's a stab at an instance of case #1, the simplest way I could come up with to model the semantics I think you are looking for (note: this is _not_ claimed to be the best way to implement the semantics, just the clearest way to express them): class An_ordered_hash include Enumerable # # A pair of hashes, indicating for each key both the value paired # with it and the order in which it was added. # def initialize @ordered = {} @hash = {} @stamp = 0 end def []=(k,v) @ordered[k] = @stamp += 1 @hash[k] = v end # # Iterators proceed in order-of-insertion # def keys_in_insertion_order keys.sort_by { |k| @ordered[k] } end def each(*args,&block) keys_in_insertion_order.each { |k| block.call(k,@hash[k]) } end alias each_pair each def each_key(*args,&block) keys_in_insertion_order.each { |k| block.call(k) } end def each_value(*args,&block) keys_in_insertion_order.each { |k| block.call(@hash[k]) } end def collect(*args,&block) keys_in_insertion_order.collect { |k| block.call(k,@hash[k]) } end # # Pass anything we don't understand through to the hash # def method_missing(method,*args,&block) @ordered.send method,*args, &block @hash.send method,*args, &block end # # A few extensions suggested by the array-like nature of the class # def <<(kv_pairs) kv_pairs.each_pair { |k,v| self[k] = v } self end def +(kv_pairs) An_ordered_hash.new << self << kv_pairs end def |(kv_pairs) self+kv_pairs end def &(kv_pairs) result = self+{} each { |k,v| result.delete(k) unless result[k] == kv_pairs[k] } result end end Since we don't have the syntactic sugar we'd like, I put together something that at least preserves the meaning & intent of it: class An_ordered_hash def to_s "_(" +collect { |k,v| "#{k}=>#{v}" }.join(')+_(')+')' end def to_str to_s end def inspect to_s end end def _(kv_pairs) An_ordered_hash.new + kv_pairs end This setup gives the following answers to the questions I'd asked previously (properly translated of course): p _(1=>2)+_(3=>4) # _(1=>2)+_(3=>4) p _(1=>2)+_(3=>4)+_(1=>5) # _(3=>4)+_(1=>5) x = _(1=>2)+_(3=>4)+_(1=>5) p x[1] # 5 x = _(1=>2) << _(3=>4) x[3] = 6 p x # _(1=>2)+_(3=>6) x = _(1=>2) << _(3=>4) x[3],x[1] = x[1],x[3] p x # _(3=>2)+_(1=>4) x = _(1=>2) << _(3=>4) x << _(7=>8) p x # _(1=>2)+_(3=>4)+_(7=>8) x = _(1=>2) << _(3=>4) x += _(7=>8) p x # _(1=>2)+_(3=>4)+_(7=>8) x = _(1=>2) << _(3=>4) x << _(1=>8) p x # _(3=>4)+_(1=>8) x = _(1=>2) << _(3=>4) x += _(1=>8) p x # _(3=>4)+_(1=>8) x = _(1=>2) << _(3=>4) x << _(7=>8) p x # _(1=>2)+_(3=>4)+_(7=>8) x = _(1=>2) << _(3=>4) x |= _(7=>8) << _(3=> 9) p x # _(1=>2)+_(7=>8)+_(3=>9) x = _(1=>2) << _(3=>4) x &= _(1=>2) << _(3=>9) << _(6=>7) p x # _(1=>2) x = _(1=>2) << _(3=>4) x << _(7=>8) p x # _(1=>2)+_(3=>4)+_(7=>8) x = _(1=>2) << _(3=>4) x[1] = 3 p x # _(3=>4)+_(1=>3) x = _(1=>2) << _(3=>4) x[1] += 1 p x # _(3=>4)+_(1=>3) x = _(1=>'2') << _(3=>'4') x[1].sub!(/2/,'3') p x # _(1=>3)+_(3=>4) x = _(1=>2) << _(3=>4) x[1] += 1 p x # _(3=>4)+_(1=>3) x = _(1=>2) << _(3=>4) x[3] = 6 x[1] = 7 p x # _(3=>6)+_(1=>7) x = _(1=>2) << _(3=>4) p x.delete(1) # 2 x[3] = 6 x[1] = 7 p x # _(3=>6)+_(1=>7) x = _(1=>2) << _(3=>4) << _(1=>5) p x.delete(1) # 5 x[3] = 6 x[1] = 7 p x # _(3=>6)+_(1=>7) Does this agree with your intuition/desires? Or am I still at sea? -- MarkusQ