2017-01-05 11 views
2

ネストされたハッシュがあり、キー/ valのペアを再配置したいと思います。以下の例は、言語のハッシュを指し示すスタイルのハッシュを示しています。ハッシュは言語タイプのハッシュを指しています。私はそれをnew_hashの例のように再フォーマットしたいと思います。私はさまざまなレベルのハッシュを繰り返し、そのようなハッシュを作成することで構造化することを理解していますが、私が心配している部分は、:styleが指し示す配列を作成し、ネストされたハッシュを繰り返して、アイテムを追加しながら配列を作成します。

コードスニペットが期待通りに機能すると想定しました。私のnew_hash:languageのキーを持ち、これは別のハッシュを指します。このハッシュは:styleというキーを持っており、それぞれの言語に関連付けられたすべてのスタイルを格納する配列を指しています。 :javascriptハッシュは、元のhashに2回存在するため、配列に2つのスタイルを持つ必要がありますが、このコードスニペットを実行すると、配列は両方のスタイルを追加しません。ハッシュを割り当てるときの1回の反復中に:javascriptにはスタイル:ooが割り当てられますが、別の繰り返しでは:functionalに置き換えられます。 配列を初期化し、ハッシュを反復処理中に複数の項目を追加する構文が不明です。

hash = { 
    :oo => { 
     :ruby => {:type => "Interpreted"}, 
     :javascript => {:type => "Interpreted"}, 
    }, 
    :functional => { 
     :scala => {:type => "Compiled"}, 
     :javascript => {:type => "Interpreted"} 
    } 
} 

new_hash = { 
    :ruby => { 
     :type => "Interpreted", :style => [:oo] 
    }, 
    :javascript => { 
     :type => "Interpreted", :style => [:oo, :functional] 
    }, 
    :scala => { 
     :type => "Compiled", :style => [:functional] 
    } 
} 

hash.each do |style, programming_language| 
    programming_language.each do |language, type| 
     type.each do |key, value| 
      new_hash[language] = {:style => [style]} 
     end 
    end 
end 
+0

「ハッシュ」に中括弧がありませんでした。これはなぜ閉じた括弧をそれ自身の行に置くべきかの良いデモンストレーションです。 – Schwern

答えて

0

これは、ハッシュを2回反復することで解決できることを認識しました。一度アレイを初期化し、2回目に必要な項目を追加します。これがハッシュを一度しか反復することができないかどうかはわかりませんが。

new = {} 
    languages.each do |style, programming_language| 
    programming_language.each do |language, type| 
     type.each do |key, value| 
     new[language] = {:type => nil , :style => []} 
     end 
    end 
    end 
    languages.each do |style, programming_language| 
    programming_language.each do |language, type| 
     type.each do |key, value| 
     new[language][:type] = value 
     new[language][:style] << style 
     end 
    end 
    end 
    new 
+0

あなたは1つのループでそれを行うことができます。内部ループをまとめて、値を追加する直前に初期化します。また、 ':style'を複数回追加します。これは' type'ループの外側にある必要があります。'type'には1つのキーしかないので動作します。 – Schwern

1

Hash::newあなたのケースでデフォルト値はこの機能は一度だけループにあなたをできるようにして

を次のように実装します {type: nil, style: []}

になるので、あなたは非実在キーのデフォルト値を指定することができます

programming_languages = { 
    :oo => { 
    :ruby => {:type => "Interpreted"}, 
    :javascript => {:type => "Interpreted"}, 
    }, 
    :functional => { 
    :scala => {:type => "Compiled"}, 
    :javascript => {:type => "Interpreted"} 
    } 
} 



programming_languages.each_with_object(Hash.new {|h,k| h[k] = {type: nil, style: []}}) do |(style,languages),obj| 
    languages.each do |language,type_hash| 
    obj[language][:style] << style 
    obj[language][:type] = type_hash[:type] 
    end 
end 

出力:

#=> {:ruby=>{:type=>"Interpreted", :style=>[:oo]}, 
    :javascript=>{:type=>"Interpreted", :style=>[:oo, :functional]}, 
    :scala=>{:type=>"Compiled", :style=>[:functional]}} 
0

ハッシュをより良い名前にしたら、簡単に解決することができます。私もsetsを使用しましたので、重複を心配する必要はありません。ハードはハッシュとサブハッシュの初期化を符号化するのではなく

require 'set' 

# Our new hash of language info. _new to differentiate between 
# the hash of languages under the hash of styles. 
languages_new = {} 

# For each style... 
styles.each do |style, languages| 
    # For each language in that style... 
    languages.each do |language, info| 
     # Add a new hash for that language if there isn't one already 
     languages_new[language] ||= {} 

     # For each bit of info about that language... 
     info.each do |key, val| 
      # Add a new set for that info if there isn't one already 
      # The `var = hash[key] ||= new_var` pattern allows 
      # conditional initialization while also using either the 
      # new or existing set. 
      set = languages_new[language][key] ||= Set.new 

      # Add the info to it 
      set.add(val) 
     end 

     # Handle the special case of style. 
     set = languages_new[language][:style] ||= Set.new 
     set.add(style) 
    end 
end 

注、私はループの各レベルでそれをやりました。つまり、すべてのキーをリストする必要はなく、新しいキーと予期しないキーを処理します。

値のセットを使用することによって、言語情報のビットが持つことができる値の数については何も仮定しません。

2

Hash#update(別名merge!)とHash#mergeの形式を使用して、両方のハッシュがマージされているときに存在するキーの値を決定するハッシュを使用できます。詳細については、ドキュメントを参照してください。

hash.each_with_object({}) do |(style,language_to_type_hash),h| 
    language_to_type_hash.each do |language,type_hash| 
    h.update(language=> { type: type_hash[:type], style: [style] }) do |_,o,_| 
     o.merge(style: [style]) { |_,ostyle_arr,nstyle_arr| ostyle_arr + nstyle_arr } 
    end 
    end 
end 
    #=> {:ruby  =>{:type=>"Interpreted", :style=>[:oo]}, 
    # :javascript=>{:type=>"Interpreted", :style=>[:oo, :functional]}, 
    # :scala  =>{:type=>"Compiled", :style=>[:functional]}} 
+0

いつもクリエイティブに加えて、 '| _、o、_ |'はブロック引数として見えます。私は笑顔になります – engineersmnky

関連する問題