比方說,我想將各個國家/地區分組到各個地區。例如,西南地區可能是:德克薩斯州,奧克拉荷馬州,科羅拉多州,新墨西哥州,猶他州,亞利桑那州,內華達州。我想要創建狀態列表並定義區域分組。我還需要能夠查找給定國家名稱的區域,例如region_for('Texas')
,這將返回'Southwest'
。將一個商品匹配到商品列表
什麼是最好的,最乾淨的,「Ruby方式」做這樣的事情?我想用簡單的'紅寶石,沒有數據庫或框架來做到這一點。
比方說,我想將各個國家/地區分組到各個地區。例如,西南地區可能是:德克薩斯州,奧克拉荷馬州,科羅拉多州,新墨西哥州,猶他州,亞利桑那州,內華達州。我想要創建狀態列表並定義區域分組。我還需要能夠查找給定國家名稱的區域,例如region_for('Texas')
,這將返回'Southwest'
。將一個商品匹配到商品列表
什麼是最好的,最乾淨的,「Ruby方式」做這樣的事情?我想用簡單的'紅寶石,沒有數據庫或框架來做到這一點。
你幾乎可以直接鍵入這個數據結構爲紅寶石...
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#select
或Enumerable#reject
,並根據值的類型進行設置。
'純'的紅寶石方式只是使用散列,然後有鍵來做你的查找。有一種類似這樣的寶石: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)
嘗試:
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
我可能會回來,並在此之後反思,我認爲它違反了一些面向對象的原則。
我建立了一個非常類似的答案,如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
一個哈希是好的,你不需要任何東西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