Ruby 按对象的数组属性元素对对象数组进行分组

Ruby 按对象的数组属性元素对对象数组进行分组,ruby,Ruby,我有一系列的城市: Bakersfield, California Interstates: ["I-5"] Oakland, California Interstates: ["I-80"] Atlanta, Georgia Interstates: ["I-20", "I-75", "I-86"] Cleveland, Ohio Interstates: ["I-71", "I-77", "I-80", "I-90"] Arlington, Texas Interstates: ["

我有一系列的城市:

Bakersfield, California
Interstates: ["I-5"]

Oakland, California
Interstates: ["I-80"]

Atlanta, Georgia
Interstates: ["I-20", "I-75", "I-86"]

Cleveland, Ohio
Interstates: ["I-71", "I-77", "I-80", "I-90"]

Arlington, Texas
Interstates: ["I-20", "I-30"]
名称、州和州际数组是每个城市的属性

我想把他们按州际划分,这样最终的结果会是这样的:

I-20: [Arlington, Atlanta]
I-5: [Bakersfield]
I-86: [Atlanta]
...
有没有快速的方法可以做到这一点

编辑:这是真正的数组,就像@wurde示例一样

cities = {
  'Bakersfield' => {
    state: 'California',
    interstate: ['I-5']
  },
  'Oakland' => {
    state: 'California',
    interstate: ['I-80']
  },
  'Atlanta' => {
    state: 'Georgia',
    interstate: ["I-20", "I-75", "I-86"]
  },
  'Cleveland' => {
    state: 'Ohio',
    interstate: ["I-71", "I-77", "I-80", "I-90"]
  },
  'Arlington' => {
    state: 'Texas',
    interstate: ["I-20", "I-30"]
  }
}
试试这个

mapping = {}

cities.each do |city|
    city.interstates.each do |interstate|
      mapping[interstate] ||= []
      mapping[interstate] << city
    end
end
mapping={}
城市。每个城市都有|
城市、州际、州际|
映射[州际]| |=[]
地图[州际]
城市={
“贝克斯菲尔德”=>{
州:'加利福尼亚',
州际:['I-5']
},
“奥克兰”=>{
州:'加利福尼亚',
州际:['I-80']
},
“亚特兰大”=>{
州:“格鲁吉亚”,
州际:[“I-20”、“I-75”、“I-86”]
},
“克利夫兰”=>{
州:“俄亥俄州”,
州际:[“I-71”、“I-77”、“I-80”、“I-90”]
},
“阿灵顿”=>{
州:“德克萨斯州”,
州际:[“I-20”、“I-30”]
}
}
州际={}
城市。每个城市都有|
城市[1][:州际公路]。每一条都有|
州际公路
州际[公路]{
#=>“I-5”=>[“贝克斯菲尔德”],
#=>“I-80”=>[“奥克兰”、“克利夫兰”],
#=>“I-20”=>[“亚特兰大”、“阿灵顿”],
#=>“I-75”=>[“亚特兰大”],
#=>“I-86”=>[“亚特兰大”],
#=>“I-71”=>[“克利夫兰”],
#=>“I-77”=>[“克利夫兰”],
#=>“I-90”=>[“克利夫兰”],
#=>“I-30”=>[“阿灵顿”]
#=> }

假设@wurde的哈希结构是真的,我会这样做

cities = {
  'Bakersfield' => {
    state: 'California',
    interstate: ['I-5']
  },
  'Oakland' => {
    state: 'California',
    interstate: ['I-80']
  },
  'Atlanta' => {
    state: 'Georgia',
    interstate: ["I-20", "I-75", "I-86"]
  },
  'Cleveland' => {
    state: 'Ohio',
    interstate: ["I-71", "I-77", "I-80", "I-90"]
  },
  'Arlington' => {
    state: 'Texas',
    interstate: ["I-20", "I-30"]
  }
}


cities.each_with_object(Hash.new {|h,k| h[k] = []}) do |(city_name,data),h|
  data[:interstate].each do |interstate|
    h[interstate] << "#{city_name}, #{data[:state]}"
  end
end
#=> {"I-5"=>["Bakersfield, California"], 
     "I-80"=>["Oakland, California", "Cleveland, Ohio"], 
     "I-20"=>["Atlanta, Georgia", "Arlington, Texas"], 
     "I-75"=>["Atlanta, Georgia"], 
     "I-86"=>["Atlanta, Georgia"], 
     "I-71"=>["Cleveland, Ohio"], 
     "I-77"=>["Cleveland, Ohio"], 
     "I-90"=>["Cleveland, Ohio"], 
     "I-30"=>["Arlington, Texas"]}
城市={
“贝克斯菲尔德”=>{
州:'加利福尼亚',
州际:['I-5']
},
“奥克兰”=>{
州:'加利福尼亚',
州际:['I-80']
},
“亚特兰大”=>{
州:“格鲁吉亚”,
州际:[“I-20”、“I-75”、“I-86”]
},
“克利夫兰”=>{
州:“俄亥俄州”,
州际:[“I-71”、“I-77”、“I-80”、“I-90”]
},
“阿灵顿”=>{
州:“德克萨斯州”,
州际:[“I-20”、“I-30”]
}
}
cities.each|u with|u object(Hash.new{h,k | h[k]=[])do|(city|u name,data),h|
数据[:州际]。每个do |州际|
h[州际]{“I-5”=>[“加利福尼亚州贝克斯菲尔德”],
“I-80”=>[“加利福尼亚州奥克兰市”、“俄亥俄州克利夫兰市”],
“I-20”=>[“佐治亚州亚特兰大”、“德克萨斯州阿灵顿”],
“I-75”=>[“佐治亚州亚特兰大”],
“I-86”=>[“佐治亚州亚特兰大”],
“I-71”=>[“俄亥俄州克利夫兰”],
“I-77”=>[“俄亥俄州克利夫兰”],
“I-90”=>[“俄亥俄州克利夫兰”],
“I-30”=>[“德克萨斯州阿灵顿”]}
我们有:

cities = {
  'Bakersfield' => ['I-5'],
  'Oakland' => ['I-80'],
  'Atlanta' => ["I-20", "I-75", "I-86"],
  'Cleveland' => ["I-71", "I-77", "I-80", "I-90"],
  'Arlington' => ["I-20", "I-30"]
}
更长版本我们可以通过以下操作获得您想要的:

require 'set'
interstates = cities.inject(Set.new){|all,item| all+item[1]} # => #<Set: {"I-5", "I-80", "I-20", "I-75", "I-86", "I-71", "I-77", "I-90", "I-30"}>
result = interstates.map{|inter| [inter, cities.select{|_,interstates| interstates.include?(inter)}.keys]}.to_h # => {"I-5"=>["Bakersfield"], "I-80"=>["Oakland", "Cleveland"], "I-20"=>["Atlanta", "Arlington"], "I-75"=>["Atlanta"], "I-86"=>["Atlanta"], "I-71"=>["Cleveland"], "I-77"=>["Cleveland"], "I-90"=>["Cleveland"], "I-30"=>["Arlington"]}
注意为了提高性能,我在这里加入了
Set
。如果您喜欢可读性,那么它会短得多,只需编写
interstates=cities.values.flatte.uniq
,正如@engineersmnky在评论中指出的那样。

使用@wurde的示例(谢谢,谢谢,谢谢):

这使用了(aka
merge!
)的形式,它使用块:

{ |_,o,n| o+n }

确定合并的两个哈希中存在的键的值。密钥是无遗嘱者(由于未使用而写入),
o
是正在构造的哈希
h
中密钥的城市数组,
n
是合并哈希
{i=>[k]}
的单个城市数组

>考虑<代码>(映射[州际][{]])菲利克斯,在这种情况下,为什么不考虑<代码>映射= HASH。新{{h,k[H][k]= []} /代码>那么它将只是<代码>映射[州际]@工程员,是的,这是另一种可能性。请您发布真数组吗?这是散列数组还是多维数组?有了真实的数据,就可以更容易地确定问题的功能性有效解决方案……当您进行此项工作时,请将其分配给一个变量(例如,
cities=[{city:“Bakersfield”,state:“California”,Interstates:[“I-5”]},…]
,因此读者可以参考
城市
,而无需对其进行定义。为什么不
州际=城市。值。展平
?我认为没有必要注入
它的性能好吗?我觉得
应该执行得更快。不过,你的版本要短得多。@engineersmnky btw,完整版本版本为
interstates=cities.values.flatte.uniq
cities.inject(Set.new){|all,item| all+item[1]}.map{|inter| [inter, cities.select{|_,interstates| interstates.include?(inter)}.keys]}.to_h
cities.each_with_object({}) do |(k,g),h|
  g[:interstate].each { |i| h.update(i=>[k]) { |_,o,n| o+n } }
end
  #=> {"I-5" =>["Bakersfield"],
  #    "I-80"=>["Oakland", "Cleveland"],
  #    "I-20"=>["Atlanta", "Arlington"],
  #    "I-75"=>["Atlanta"],
  #    "I-86"=>["Atlanta"],
  #    "I-71"=>["Cleveland"],
  #    "I-77"=>["Cleveland"],
  #    "I-90"=>["Cleveland"],
  #    "I-30"=>["Arlington"]} 
{ |_,o,n| o+n }