假设我想将国家分为几个区域。例如,西南地区可能是:德克萨斯州,俄克拉荷马州,科罗拉多州,新墨西哥州,犹他州,亚利桑那州,内华达州。
不知何故,我需要创建状态列表并定义区域分组。我还需要能够查找给定状态名称的区域,例如region_for('Texas')
,它将返回'Southwest'
。
最好,最干净,“Ruby Way”做这样的事情是什么?我想使用普通的'ol ruby,没有数据库或框架。
答案 0 :(得分:1)
'纯'ruby方式只是使用哈希,然后有键来进行查找。有一种宝石可以做这样的事情: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)
答案 1 :(得分:1)
你几乎可以直接在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
这会产生一个Hash,它既有状态又有区域作为彼此识别的键。数据结构类似于:
{"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
来执行此操作。
答案 2 :(得分: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
我可能会稍后回过头来反思,我认为它违反了一些OO原则。
答案 3 :(得分: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
答案 4 :(得分:0)
Hash很好,你不需要任何更好的东西。
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