从多个哈希表中创建深度为3的哈希表

3

我会尝试将由多个键值对组成的深度为一的哈希数组转换为一个新的哈希表,以包含所有这些数据。

我的数据:

a = {'name' => 200, 'segment' => 'alpha',  'dc' => 'nyc', 'designation' => 'web'}
b = {'name' => 201, 'segment' => 'shared', 'dc' => 'nyc', 'designation' => 'generic'}
c = {'name' => 202, 'segment' => 'alpha', 'dc' => 'nyc', 'designation' => 'app'}
d = {'name' => 400, 'segment' => 'alpha',  'dc' => 'sfc', 'designation' => 'web'}
e = {'name' => 401, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'web'}
f = {'name' => 402, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'app'}
g = {'name' => 403, 'segment' => 'alpha', 'dc' => 'sfc', 'designation' => 'app'}

members = [a,b,c,d,e,f,g]

这是我期望得到的内容:

{
  :alpha => {
    :nyc => {
      :web => [200],
      :app => [202]
    },
    :sfc => {
      :web => [400],
      :app => [403],
    }
  },
  :shared => {
    :nyc => {
       generic => [201]
    },
    :sfc => {
      :app => [402],
      :web => [401]
    }
  }
}

这是我的代码(至少是开始部分...)。
members.each do |m|
  if m.key? 'segment'
    dict[m['segment']] = {} unless dict.key? m['segment']
  end
  puts m['dc']
  if m.key? 'dc'
    dict[m['segment']] = m['dc']
    #dict[m['segment']['dc']] = m['segment']['dc']# unless dict[m['segment']].key? m['dc']
  end

我尝试了各种代码变化,结果如下:

{"alpha"=>"sfc", "shared"=>"sfc"}
{"alpha"=>{"sfc"=>{}}, "shared"=>{"sfc"=>{}}}
{"alpha"=>{"sfc"=>{}}, nil=>{"web"=>[]}, "shared"=>{"sfc"=>{}}}

我需要搜索哪些热门词汇来理解这个问题?

谢谢。


{btsdaf} - tokland
@tokland,抱歉,是因为手机复制粘贴的问题搞混了。很好地发现了!现在清楚了吗? - ARL
{btsdaf} - hoffm
2个回答

2
members.group_by { |g| g['segment'] }.
        transform_values { |a| a.group_by { |f| f['dc'] }.
          transform_values { |aa| aa.group_by { |h| h['designation'] }.
            transform_values { |aaa| aaa.map { |e| e['name'] } } } }
  #=> { "alpha"=>{
          "nyc"=>{
             "web"=>[200],
             "app"=>[202]
          },
          "sfc"=>{
             "web"=>[400],
             "app"=>[403]
          }
        },
        "shared"=>{
          "nyc"=>{
            "generic"=>[201]
          },
          "sfc"=>{
            "web"=>[401],
            "app"=>[402]
          }
        }
      }

请参见Enumerable#group_byHash#transform_values文档。后者于Ruby v2.4中首次亮相。
对于早于2.4版本的Ruby,可以很容易地创建Hash#tranform_values方法。
class Hash
  def transform_values
    Hash[map { |k,v| [k, yield(v)] }]
  end
end

那么,例如,
{ a: 1, b: 3 }.transform_values { |v| 2*v }
  #=> { :a=>2, :b=>6 }

{btsdaf} - ARL
1
{btsdaf} - Cary Swoveland

1
在Ruby 2.3和2.0中(没有transform_values,使用group_by):
a = {'name' => 200, 'segment' => 'alpha',  'dc' => 'nyc', 'designation' => 'web'}
b = {'name' => 201, 'segment' => 'shared', 'dc' => 'nyc', 'designation' => 'generic'}
c = {'name' => 202, 'segment' => 'alpha', 'dc' => 'nyc', 'designation' => 'app'}
d = {'name' => 400, 'segment' => 'alpha',  'dc' => 'sfc', 'designation' => 'web'}
e = {'name' => 401, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'web'}
f = {'name' => 402, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'app'}
g = {'name' => 403, 'segment' => 'alpha', 'dc' => 'sfc', 'designation' => 'app'}

members = [a,b,c,d,e,f,g]

h1 = members.group_by { | gr | gr['segment'] }
p h1
#           in h1 at key k1 put this new value
h1.each { | k1, v1 | h1[k1] = v1.group_by { | gr | gr['dc'] } }
puts
p h1
h1.each { | k1, v1 | v1.each { | k2, v2 | v1[k2] = v2.group_by { | gr | gr['designation'] } } }
puts
p h1
h1.each { | k1, v1 | v1.each { | k2, v2 | v2.each { | k3, v3 | v2[k3] = v3.collect { | el | el['name'] } } } }
puts '--- final result ---'
p h1

也许在没有使用group_by的Ruby 1.8版本中:
a = {'name' => 200, 'segment' => 'alpha',  'dc' => 'nyc', 'designation' => 'web'}
b = {'name' => 201, 'segment' => 'shared', 'dc' => 'nyc', 'designation' => 'generic'}
c = {'name' => 202, 'segment' => 'alpha', 'dc' => 'nyc', 'designation' => 'app'}
d = {'name' => 400, 'segment' => 'alpha',  'dc' => 'sfc', 'designation' => 'web'}
e = {'name' => 401, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'web'}
f = {'name' => 402, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'app'}
g = {'name' => 403, 'segment' => 'alpha', 'dc' => 'sfc', 'designation' => 'app'}

members = [a,b,c,d,e,f,g]

puts '=== without group_by ==='

class Array # reopen class Array
    def groupedByKey(p_key)
        new_h = {}

        self.each do | el | # el must be a hash
            key = el[p_key]
            unless new_h[key]
            then # the key does not exist, create a key - value pair
                new_h[key] = [el] # the value is an array with the whole element
            else # a key and value already exist ...
                new_h[key] << el # ... push the new value onto the array
            end
        end

        new_h
    end
end # class Array

h1 = members.groupedByKey('segment')
p h1
h1.each { | k1, v1 | h1[k1] = v1.groupedByKey('dc') }
puts
p h1
h1.each { | k1, v1 | v1.each { | k2, v2 | v1[k2] = v2.groupedByKey('designation') } }
puts
p h1
h1.each { | k1, v1 | v1.each { | k2, v2 | v2.each { | k3, v3 | v2[k3] = v3.collect { | el | el['name'] } } } }
puts '--- final result ---'
p h1

执行(在2.0中):

$ ruby -w t2.rb 
=== without group_by ===
{"alpha"=>[{"name"=>200, "segment"=>"alpha", "dc"=>"nye",
...
--- final result ---
{"alpha"=>{"nyc"=>{"web"=>[200], "app"=>[202]}, "sfc"=>{"web"=>[400], "app"=>[403]}},
"shared"=>{"nyc"=>{"generic"=>[201]}, "sfc"=>{"web"=>[401], "app"=>`[402]}}}

编辑

结合Cary的Hash#transform_values

a = {'name' => 200, 'segment' => 'alpha',  'dc' => 'nyc', 'designation' => 'web'}
b = {'name' => 201, 'segment' => 'shared', 'dc' => 'nyc', 'designation' => 'generic'}
c = {'name' => 202, 'segment' => 'alpha', 'dc' => 'nyc', 'designation' => 'app'}
d = {'name' => 400, 'segment' => 'alpha',  'dc' => 'sfc', 'designation' => 'web'}
e = {'name' => 401, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'web'}
f = {'name' => 402, 'segment' => 'shared', 'dc' => 'sfc', 'designation' => 'app'}
g = {'name' => 403, 'segment' => 'alpha', 'dc' => 'sfc', 'designation' => 'app'}

members = [a,b,c,d,e,f,g]

puts '=== should work in Ruby 1.8 ==='

class Array # reopen class Array
    def groupedByKey(p_key)
        new_h = {}

        self.each do | el | # el must be a hash
            key = el[p_key]
            unless new_h[key]
            then # the key does not exist, create a key - value pair
                new_h[key] = [el] # the value is an array with the whole element
            else # a key and value already exist ...
                new_h[key] << el # ... push the new value onto the array
            end
        end

        new_h
    end
end # class Array

class Hash
    def transformValues
        Hash[self.collect { | k, v | [ k, yield(v) ] } ]
    end
end

# Step by step
h1 = members.groupedByKey('segment')
puts '--- grouped by segment'
p h1
h2 = h1.transformValues { | v1 | v1.groupedByKey('dc') }
puts '--- grouped by dc'
p h2
h2 = members.groupedByKey('segment').
     transformValues { | v1 | v1.groupedByKey('dc').
        transformValues { | val | val.groupedByKey('designation') } }
puts '--- grouped by designation'
p h2

# One step.
# Note that the hash returned by each groupedByKey is immediately transformed
# (watch the dot after groupedByKey('xxx')).
h2 = members.groupedByKey('segment').
     transformValues { | v1 | v1.groupedByKey('dc').
        transformValues { | v2 | v2.groupedByKey('designation').
            transformValues { | v3 | v3.collect { | el | el['name'] } } } }
puts '--- final result ---'
p h2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接