2011-09-23 66 views
0

比方說,我想將各個國家/地區分組到各個地區。例如,西南地區可能是:德克薩斯州,奧克拉荷馬州,科羅拉多州,新墨西哥州,猶他州,亞利桑那州,內華達州。我想要創建狀態列表並定義區域分組。我還需要能夠查找給定國家名稱的區域,例如region_for('Texas'),這將返回'Southwest'將一個商品匹配到商品列表

什麼是最好的,最乾淨的,「Ruby方式」做這樣的事情?我想用簡單的'紅寶石,沒有數據庫或框架來做到這一點。

回答

1

你幾乎可以直接鍵入這個數據結構爲紅寶石...

result = { 
    'Southwest' => %W{Texas Oklahoma Colorado New\ Mexico Utah Arizona Nevada}, 
    'West'  => %W{California Oregon Washington}, 
}.inject({}) do |m, (k, v)| 
    m[k] = v 
    v.each { |s| m[s] = k } 
    m 
end 

這產生了一個單一的散列,它具有狀態和區域作爲彼此識別的關鍵字。數據結構如下所示:

{"Colorado" => "Southwest", 
"New Mexico" => "Southwest", 
"Oklahoma" => "Southwest", 
"California" => "West", 
"Oregon"  => "West", 
"Texas"  => "Southwest", 
"Washington" => "West", 
"Utah"  => "Southwest", 
"Nevada"  => "Southwest", 
"Arizona" => "Southwest" 
"Southwest" => 
    ["Texas", "Oklahoma", "Colorado", "New Mexico", "Utah", "Arizona", "Nevada"], 
"West" => 
    ["California", "Oregon", "Washington"], 
} 

另一種方法會爲狀態創建單獨的散列。然後,您可以通過使用Hash#keys獲取區域或州的列表,但您也可以在此處使用Enumerable#selectEnumerable#reject,並根據值的類型進行設置。

1

'純'的紅寶石方式只是使用散列,然後有鍵來做你的查找。有一種類似這樣的寶石:ruport。看看源代碼可能是值得的。對於已說明的使用情況下,我會碰到這樣的:

class RegionMapper 
    #potentially put this in a config file 
    REGIONS = Hash[[['California', 'Southwest'], ...]] 

    def initialize 
    @region_map = REGIONS.inject({}) {|r, e| r[e.second] ||= []; r[e.second] << e.first; r} 
    end 

    def region_for_state(state) 
    REGIONS[state] 
    end 
    def states_for_region(region) 
    @region_map(region) 
    end 
end 

的一點是,有效率,你想有一個哈希做你想要搜索的每個鍵查找。但是你不想'暴露數據重複,所以你把它放在一個班級。

如果你有多個值/鍵,那麼你真的有一個表。如果你想保持恆定時間的查找,那麼你構建每一列的哈希(如@region_map)

0

嘗試:

class State 
    attr_accessor :name, :region 

    def initialize(name, region=nil) 
    @name = name 
    @region = region 
    end 
end 

class Region 
    attr_accessor :name, :states 

    def initialize(name, states) 
    @name = name 
    @states = states 
    end 

    def set_state_regions 
    self.states.each {|state| state.region = self.name} 
    end 
end 

mo = State.new("missouri") 
il = State.new("illionois") 
oh = State.new("ohio") 

midwest = Region.new("midwest", [mo, il, oh]) 
midwest.states.each {|state| puts state.name} 
midwest.set_state_regions 

我可能會回來,並在此之後反思,我認爲它違反了一些面向對象的原則。

0

我建立了一個非常類似的答案,如Caley

主要區別:我將數據存儲在yaml結構中。

require 'yaml' 

class Region 
    @@all = {} 
    def self.[](key) 
    @@all[key] 
    end 
    def initialize(name) 
    @name = name 
    @states = [] 
    @@all[@name] = self 
    end 
    def <<(state) 
    @states << state 
    state.region = state 
    end 
    def each_state 
    @states.each{|state| yield state } if block_given? 
    @states 
    end 
    attr_reader :name 
end 

class State 
    @@all = {} 
    def self.[](key) 
    @@all[key] 
    end 
    def initialize(name, region = nil) 
    @name = name 
    @region = region 
    @@all[@name] = self 
    end 
    attr_accessor :name 
    attr_accessor :region 
end 

YAML.load(DATA).each{|region,states| 
    r = Region.new(region) 
    states.each{|state| r << State.new(state) } 
} 

p Region['Southwest Region'] 
p Region['Southwest Region'].each_state 
Region['Southwest Region'].each_state{|state| 
    p state.name 
} 


__END__ 
Southwest Region: 
- Texas 
- Oklahoma 
- Colorado 
- New Mexico 
- Utah 
- Arizona 
- Nevada. 
Pacific: 
- California 
- Oregon 
- Washington 
0

一個哈希是好的,你不需要任何東西fancier這個。

region = { 
    "Maine" => "New England", 
    "New Hampshire" => "New England", 
    etc 
} 

然後您可以使用像

region["Maine"] 

或者,如果你想要更多的設置它緊湊,像這樣:

regions = { 
    "Southwest" => ["Texas", "Oklahoma", "Colorado", "New Mexico", "Utah", "Arizona", "Nevada"], 
    "New England" => ["Maine", "New Hampshire", "Vermont", "Massachusetts","Rhode Island", "Connecticut"], 
    etc 
} 
region = {} 
regions.each do |r,states| 
    states.each do |state| 
    region[state] = r 
    end 
end