在ruby中将笛卡尔乘积转换为嵌套哈希

在ruby中将笛卡尔乘积转换为嵌套哈希,ruby,hash,Ruby,Hash,我有一个笛卡尔积的结构,看起来像这样(可以延伸到任意深度) 。。。它有一个固定的结构,但我想要简单的索引,所以我尝试编写一个方法将其转换为: nested = { "a"=> { "a"=> 1, "b"=> 2 }, "b"=> { "a"=> 3, "b"=> 4 } } 任何聪明的想法(允许任意深度)?可能是这样的(不是最干净的方式): 结果: puts cart

我有一个笛卡尔积的结构,看起来像这样(可以延伸到任意深度)

。。。它有一个固定的结构,但我想要简单的索引,所以我尝试编写一个方法将其转换为:

nested = {
   "a"=> { 
     "a"=> 1,
     "b"=> 2
    },
   "b"=> { 
     "a"=> 3,
     "b"=> 4
         }
    }
任何聪明的想法(允许任意深度)?

可能是这样的(不是最干净的方式):

结果:

puts cartesian_to_map(myhash).inspect
{"a"=>{"a"=>1, "b"=>2}, "b"=>{"a"=>3, "b"=>4}}
可能是这样(不是最干净的方式):

结果:

puts cartesian_to_map(myhash).inspect
{"a"=>{"a"=>1, "b"=>2}, "b"=>{"a"=>3, "b"=>4}}

下面是一个丑陋但有效的解决方案:

nested = Hash[ myhash.group_by{ |h,n| h["var1"] } ].tap{ |nested|
  nested.each do |v1,a|
    nested[v1] = a.group_by{ |h,n| h["var2"] }
    nested[v1].each{ |v2,a| nested[v1][v2] = a.flatten.last }
  end
}

p nested
#=> {"a"=>{"a"=>1, "b"=>2}, "b"=>{"a"=>3, "b"=>4}}

您可以考虑一种更容易映射到(和IMO)的替代表达式,同样容易索引:

paired = Hash[ myhash.map{ |h,n| [ [h["var1"],h["var2"]], n ] } ]

p paired
#=> {["a", "a"]=>1, ["a", "b"]=>2, ["b", "a"]=>3, ["b", "b"]=>4}

p paired[["a","b"]]
#=> 2

下面是一个丑陋但有效的解决方案:

nested = Hash[ myhash.group_by{ |h,n| h["var1"] } ].tap{ |nested|
  nested.each do |v1,a|
    nested[v1] = a.group_by{ |h,n| h["var2"] }
    nested[v1].each{ |v2,a| nested[v1][v2] = a.flatten.last }
  end
}

p nested
#=> {"a"=>{"a"=>1, "b"=>2}, "b"=>{"a"=>3, "b"=>4}}

您可以考虑一种更容易映射到(和IMO)的替代表达式,同样容易索引:

paired = Hash[ myhash.map{ |h,n| [ [h["var1"],h["var2"]], n ] } ]

p paired
#=> {["a", "a"]=>1, ["a", "b"]=>2, ["b", "a"]=>3, ["b", "b"]=>4}

p paired[["a","b"]]
#=> 2
这是我的例子

它使用一个方法
索引(散列,字段)
,该方法接受散列和要索引的字段

它是脏的,并使用局部变量向上传递索引中的当前级别

我打赌你能把它做得更好

def index(hash, fields)
  # store the last index of the fields
  last_field = fields.length - 1

  # our indexed version
  indexed = {}

  hash.each do |key, value|
    # our current point in the indexed hash
    point = indexed
    fields.each_with_index do |field, i|
      key_field = key[field]
      if i == last_field
        point[key_field] = value
      else
        # ensure the next point is a hash
        point[key_field] ||= {}
        # move our point up
        point = point[key_field]
      end
    end
  end
  # return our indexed hash
  indexed
end
然后你就可以打电话了

index(myhash, ["var1", "var2"])
它应该看起来像你想要的

index({
  {"var1"=>"a", "var2"=>"a"} => 1,
  {"var1"=>"a", "var2"=>"b"} => 2,
  {"var1"=>"b", "var2"=>"a"} => 3,
  {"var1"=>"b", "var2"=>"b"} => 4,
}, ["var1", "var2"])

==

{
  "a"=> { 
    "a"=> 1,
    "b"=> 2
  },
  "b"=> { 
    "a"=> 3,
    "b"=> 4
  }
}
它似乎起作用了。 (将其视为要点 )这是我的例子

它使用一个方法
索引(散列,字段)
,该方法接受散列和要索引的字段

它是脏的,并使用局部变量向上传递索引中的当前级别

我打赌你能把它做得更好

def index(hash, fields)
  # store the last index of the fields
  last_field = fields.length - 1

  # our indexed version
  indexed = {}

  hash.each do |key, value|
    # our current point in the indexed hash
    point = indexed
    fields.each_with_index do |field, i|
      key_field = key[field]
      if i == last_field
        point[key_field] = value
      else
        # ensure the next point is a hash
        point[key_field] ||= {}
        # move our point up
        point = point[key_field]
      end
    end
  end
  # return our indexed hash
  indexed
end
然后你就可以打电话了

index(myhash, ["var1", "var2"])
它应该看起来像你想要的

index({
  {"var1"=>"a", "var2"=>"a"} => 1,
  {"var1"=>"a", "var2"=>"b"} => 2,
  {"var1"=>"b", "var2"=>"a"} => 3,
  {"var1"=>"b", "var2"=>"b"} => 4,
}, ["var1", "var2"])

==

{
  "a"=> { 
    "a"=> 1,
    "b"=> 2
  },
  "b"=> { 
    "a"=> 3,
    "b"=> 4
  }
}
它似乎起作用了。 (将其视为要点
)

稍好一些:
myhash.each{k,v|(hash[k[“var1”]].\124;={}.merge!({k[“var2”]=>v})
谢谢,但我恐怕需要任意/递归深度(即var3、var4等)稍好一些:
myhash.each{k,v}(hash[k[“var1”]]].}.merge!{,但我恐怕需要任意/递归深度(即var3、var4等)