2016-10-31 6 views
1

Rubyでセットを保持するための2次元ハッシュを作成したいと思います。次のコードでは、4つの異なるセットを保持し、ハッシュの最初の次元のキーをリストすることができると期待しています。セットや配列を2次元のRubyハッシュにするには?

require 'set' 

cities = Hash.new() 
cities['Europe'] = Hash.new(Set.new) 
cities['Asia'] = Hash.new(Set.new) 

cities['Europe']['Sweden'].add "Stockholm" 
cities['Europe']['Sweden'].add "Gothenburg" 
cities['Europe']['Denmark'].add "Copenhagen" 
cities['Europe']['Denmark'].add "Odense" 

cities['Asia']['Japan'].add "Tokyo" 
cities['Asia']['Japan'].add "Kyoto" 
cities['Asia']['China'].add "Beijing" 
cities['Asia']['China'].add "Shanghai" 

p cities['Europe'] 
p cities['Asia'] 

p cities['Europe']['Sweden'] 
p cities['Asia']['Japan'] 

私は、次のような出力が得られます。

{} 
{} 
#<Set: {"Stockholm", "Gothenburg", "Copenhagen", "Odense"}> 
#<Set: {"Tokyo", "Kyoto", "Beijing", "Shanghai"}> 

ハッシュとセットの実装が互いに干渉し、私は、この直感的な結果を得るように思え。セットの代わりにSet.newArray.newに置き換え、.add.pushに置き換えた場合、同じ結果が得られます。

(Rubyのバージョン:ルビー2.3.1p112)

答えて

3

h = Hash.new(Set.new)をやって、Setのインスタンスになりますハッシュに存在しないキーにアクセスしたときに返されるデフォルト値、同じセットを意味しています共有。それにアクセスする際にハッシュが移入されていないことを意味し、ハッシュに存在しないキーにアクセスするとき

h = Hash.new(Set.new) 
h["Sweden"] << "Stockholm" 
# => #<Set: {"Stockholm"}> 
h["Denmark"] << "Copenhagen" 
# => #<Set: {"Stockholm", "Copenhagen"}> 
h["Sweden"].object_id == h["Denmark"].object_id 
# => true 

はまた、それはデフォルト値を返します:あなたはそれをこのように確認することができます。

h = Hash.new(Set.new) 
h["Sweden"] 
# => #<Set: {}> 
h 
# => {} 

Hash.newを呼び出すブロックを指定することができます。ブロックは、ハッシュに存在しないキーにアクセスするときに、ハッシュとキーで呼び出されます。ブロックはデフォルト値を返す必要があります。あなたがそうのように、ハッシュにSetの別のインスタンスを保存することができる場所です。

h = Hash.new { |hash, key| hash[key] = Set.new } 
h["Sweden"] << "Stockholm" 
# => #<Set: {"Stockholm"}> 
h["Denmark"] << "Copenhagen" 
# => #<Set: {"Copenhagen"}> 
h 
# => {"Sweden"=>#<Set: {"Stockholm"}>, "Denmark"=>#<Set: {"Copenhagen"}>} 

あなたは各大陸のハッシュを設定しないように、それらを組み合わせることができます。

cities = Hash.new do |continents, continent_name| 
    continent_countries = Hash.new { |countries, country_name| countries[country_name] = Set.new } 
    continents[continent_name] = continent_countries 
end 
cities["Europe"]["Sweden"] << "Stockholm" 
cities["Europe"]["Denmark"] << "Copenhagen" 
cities["Asia"]["Japan"] << "Tokyo" 
cities["Asia"]["Japan"] << "Kyoto" 
cities 
# => {"Europe"=>{"Sweden"=>#<Set: {"Stockholm"}>, "Denmark"=>#<Set: {"Copenhagen"}>}, 
# "Asia"=>{"Japan"=>#<Set: {"Tokyo", "Kyoto"}>}} 
3

トラブルます。.. 。

cities['Europe'] = Hash.new(Set.new) 
cities['Asia'] = Hash.new(Set.new) 

...各キーのためにあなたは、同じオブジェクト(Hash.newのインスタンス)であることをデフォルトに設定していると、そのオブジェクトは、都市のすべてのメンバー[「ヨーロッパ」]のために同じオブジェクトです。プラス.addを使用しても、実際にハッシュキーをインスタンス化するわけではなく、基礎となるデフォルトのSetを追加するだけです。

代わりにブロックを使用しても問題ありませんが、ブロック内のデフォルトを明示的にハッシュに格納する必要があります。

cities['Europe'] = {|hash, key| hash[key] = Set.new} 
cities['Asia'] = {|hash, key| hash[key] = Set.new} 

ボーナス提案...

あなたが明示的に各大陸のハッシュを作成する必要はありませんように、ネストされたHash.newブロックとcitiesハッシュを作成することができます...

cities = Hash.new{|hash,key| hash[key] = Hash.new{|country_hash, country| country_hash[country] = Set.new } } 

...これはあなたがいない大陸によって、国によってようになりましセットが分解されたかったですが、それは、より読みやすい場合

{"Europe"=>{"Sweden"=>#<Set: {"Stockholm", "Gothenburg"}>, "Denmark"=>#<Set: {"Copenhagen", "Odense"}>}} 
{"Sweden"=>#<Set: {"Stockholm", "Gothenburg"}>, "Denmark"=>#<Set: {"Copenhagen", "Odense"}>} 
#<Set: {"Stockholm", "Gothenburg"}> 
#<Set: {"Copenhagen", "Odense"}> 

わからない:以下の出力を返します

require 'set' 

cities = Hash.new{|h,k| h[k] = Hash.new{|h, k| h[k] = Set.new}} 

cities['Europe']['Sweden'].add "Stockholm" 
cities['Europe']['Sweden'].add "Gothenburg" 
cities['Europe']['Denmark'].add "Copenhagen" 
cities['Europe']['Denmark'].add "Odense" 

cities['Asia']['Japan'].add "Tokyo" 
cities['Asia']['Japan'].add "Kyoto" 
cities['Asia']['China'].add "Beijing" 
cities['Asia']['China'].add "Shanghai" 

p cities['Europe'] 
=> {"Sweden"=>#<Set: {"Stockholm", "Gothenburg"}>, "Denmark"=>#<Set: {"Copenhagen", "Odense"}>} 
p cities['Asia'] 
=> {"Japan"=>#<Set: {"Tokyo", "Kyoto"}>, "China"=>#<Set: {"Beijing", "Shanghai"}>} 

p cities['Europe']['Sweden'] 
=> #<Set: {"Stockholm", "Gothenburg"}> 
p cities['Asia']['Japan'] 
=>#<Set: {"Tokyo", "Kyoto"}> 
0
cities = Hash.new() 
cities['Europe'] = Hash.new 

sweden_set = Set.new ["Stockholm"] 
cities['Europe']['Sweden'] = sweden_set 
sweden_set.add("Gothenburg") 
denmark_set = ["Copenhagen", "Odense"].to_set 
cities['Europe']['Denmark'] = denmark_set 

p cities 
p cities['Europe'] 
p cities['Europe']['Sweden'] 
p cities['Europe']['Denmark'] 

この印刷し
require 'set' 
cities = Hash.new() 

cities['Asia'] = {} 
cities['Europe'] = {} 

cities['Asia']["Japan"] = Set.new ["Tokyo","Kyoto"] 
cities['Asia']["China"] = Set.new ["Beijing", "Shangai"] 

cities['Europe']["Sweden"] = Set.new ["Stockholm","Gothenburg"] 
cities['Europe']["Denmark"] = Set.new ["Copenhagen", "Odense"] 

p cities 
p cities['Asia']['Japan'] 
p cities['Asia']['Japan'].first 
p cities['Europe']['Sweden'] 

{"Asia"=>{"Japan"=>#<Set: {"Tokyo", "Kyoto"}>, "China"=>#<Set: {"Beijing", "Shangai"}>}, "Europe"=>{"Sweden"=>#<Set: {"Stockholm", "Gothenburg"}>, "Denmark"=>#<Set: {"Copenhagen", "Odense"}>}} 
#<Set: {"Tokyo", "Kyoto"}> 
"Tokyo" 
#<Set: {"Stockholm", "Gothenburg"}> 
+1

良い努力を私はあなたにもこのような何かを行うことが奇妙だったものの一部は、あなたがキー

ハッシュにセットを割り当てることはなかったと思います、トーマス、しかし、弱点は、大陸と国に都市を追加することです、あなたは国の鍵が存在するかどうかを知る必要があります...私は後で都市[アジア] [' Japan '] '日本のSetがすでに存在するかどうかをテストするコードを書く必要があります。 – SteveTurczyn

+0

True、初期化されたセット 'cities ['Asia'] [" Japan "] = Set.new'で各国を開始し、各国セットに都市を追加することができます。 '都市 '[アジア]] [日本]。add('東京 ')' –

+1

はい、しかしすべての国を事前定義する必要があります。 OPがしようとしているのは、 '' [Europe '] [' Sweden '] 'を参照しているだけで、それがうまくいくと、後でデータ' 'Europe' '[' France ']'自動的に動作します。彼の基本的なテクニックは悪くありませんでしたが、 '都市['Europe'] = Hash.new(Set.new)'が各国が指し示す共通のオブジェクトを作成することを認識していませんでした。国)。 – SteveTurczyn

関連する問題