2017-10-23 8 views
3

ハッシュの配列を取ろうとしていますが、それぞれが複数のキーと値を持つ深さが1つあり、すべてのデータを組み込んだ新しいハッシュを作成しようとしています。複数のハッシュから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 

私のコードのさまざまなバリエーションを試しました。私はgですような結果etting:

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

を、私はこれを理解するために検索する必要が流行語は何ですか?

おかげで、

+0

申し訳ありませんが、私が期待される出力の一部を理解していません。たとえば: ':alpha - >:nyc - >:app'のようになります。このトリプレットを持つメンバーはいませんが、どこから来たのですか? 'ヌル'はどう? 'ジェネリック'はどうですか? – tokland

+0

@tokland携帯電話からの私の謝罪、コピー&ペーストの問題と混在物。いいキャッチ!それは今はっきりしていますか? – ARL

+0

'dict'とは何ですか?それは空のハッシュとして始まりますか? – hoffm

答えて

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

Enumerble#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 } 
+0

私は1.8を使用しています(私の選択ではありません)ので、私は確かにgroup_byをチェックアウトします。 – ARL

+1

Egad!私たちはv1.8.7があったときに蒸気機関車を持っていました。 v.1.8.7で動作するはずの 'transform_values'をロールアップする方法を示すために編集しました。 –

1
ルビー2.3

及び2.0(group_byと、transform_valuesなし):

ルビー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] 

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なし):

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)0

実行:ケーリーのHash#transform_valuesと組み合わせる

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

EDIT:

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 
+0

編集済み、1.8で動作するはずです。 – BernardK

関連する問題