Hi,

At Tue, 27 Aug 2002 07:14:19 +0900,
Philip Mak wrote:
> When programming radio buttons on a website, I find myself using this
> sort of construct a lot:
> 
>     @choices = [
>         ['1', 'Spring'],
>         ['2', 'Summer'],
>         ['3', 'Fall']
>     ]
> 
>     @table = {}
>     @choices.each do |key, value|
>         @table[key] = value
>     end
> 
> The data structure I really want is like a hash, except that it
> maintains its key/value pairs in the order that I defined them.
> 
> Or, looking at it another way, I want an array of arrays, except that
> it can be accessed using the key (where the key is the first element
> of each array inside the outer array).

What about this?

require 'delegate'

class Hash
  class Ordered < DelegateClass(Hash)
    def initialize(*array)
      super({})
      @order = []
      array.each(&method(:store))
    end

    def each
      @order.each do |key|
	yield key, fetch(key)
      end
    end

    def store(key, val)
      has_key?(key) or @order << key
      super
    end

    def shift
      return if @order.empty?
      key = @order.shift
      [key, delete(key)]
    end

    def self.[](*array)
      new(*array)
    end
  end

  def self.Ordered(*array)
    Ordered.new(*array)
  end
end

if __FILE__ == $0
  array = [
    ['3', 'Fall'],
    ['1', 'Spring'],
    ['2', 'Summer'],
  ]
  nh = Hash[*array.flatten]
  nh.each {|x| p x}
  oh = Hash::Ordered[*array]
  oh.each {|x| p x}
  while x = oh.shift
    p x
  end
end

-- 
Nobu Nakada