2011-08-04 45 views
1

我有一个笛卡尔积看起来像这样(并且可以出去任意深度)的结构......转换笛卡尔乘积嵌套散列红宝石

variables = ["var1","var2",...] 
myhash = { 
    {"var1"=>"a", "var2"=>"a", ...}=>1, 
    {"var1"=>"a", "var2"=>"b", ...}=>2, 
    {"var1"=>"b", "var2"=>"a", ...}=>3, 
    {"var1"=>"b", "var2"=>"b", ...}=>4, 
} 

...它有一个固定的结构但我想简单的索引,所以我想写一个方法将其转换为这样的:

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

任何巧妙的构思(即允许任意深度)?

回答

0

这是我的例子。

它使用一种方法index(hash, fields),该方法采用散列,以及要索引的字段。

它很脏,并且使用局部变量传递索引中的当前级别。

我敢打赌,你可以使它更好。

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 
    } 
} 

似乎什么工作。 (看作是一个要点 https://gist.github.com/1126580

+0

你摇滚马太,谢谢! – hooks

1

也许是这样的(不是干净的方式):

def cartesian_to_map(myhash) 
    {}.tap do |hash| 
    myhash.each do |h| 
     (hash[h[0]["var1"]] ||= {}).merge!({h[0]["var2"] => h[1]}) 
    end 
    end 
end 

结果:

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

略好:'myhash.each {| k,v | (hash [k [“var1”]] || = {})。merge!({k [“var2”] => v})}' – Phrogz

+0

谢谢,但恐怕我需要任意/递归深度var3,var4等) – hooks

0

这里是一个丑陋的,但有效的解决方案:

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