雜湊型態


在Ruby中,雜湊物件是儲存鍵(Key)/值(Value)對應的物件,為Hash的實例。直接示範如何以實字建立雜湊物件:
>> passwords = {"Justin" => 123456, "caterpillar" => 933933}
=> {"Justin"=>123456, "caterpillar"=>933933}
>> passwords["Justin"]
=> 123456
>> passwords["caterpillar"]
=> 933933
>> passwords["Hamimi"] = 970221
=> 970221
>> passwords
=> {"Justin"=>123456, "caterpillar"=>933933, "Hamimi"=>970221}
>> passwords["Hamimi"]
=> 970221
>> passwords.delete("caterpillar")
=> 933933
>> passwords
=> {"Justin"=>123456, "Hamimi"=>970221}
>> passwords.delete("XD")
=> nil
>> passwords.delete("XD") { |key| "no such key #{key}" }
=> "no such key XD"
>>


建立雜湊時,每個鍵物件(在上例中是字串,也可以是任何物件)會用來取得對應的值物件,指定鍵物件取得值物件時是使用[]操作。建立雜湊物件後,可以隨時再加入鍵/值。如果要刪除某個鍵/值,則可以使用delete方法,如果指定的鍵存在,delete會傳回對應的值,若鍵不存在,預設會傳回nildelete也可以指定區塊,若鍵不存在,區塊傳回值就是delete的傳回值。

直接使用實字建立雜湊,若指定鍵要取得值時,雜湊中沒有該鍵的存在,則會傳回nil,若使用fetch方法指定鍵取值,在鍵不存在時會引發KeyError例外,如果有指定fetch的第二個引數,則鍵不存在時會傳回指定的第二個引數。可以使用key?、hash_key?、member?、include?等方法來測試鍵是否存在於字典中,可以使value?has_value?方法測試指定的值是否存在。例如:
>> passwords["XD"]
=> nil
>> passwords.fetch("XD")
KeyError: key not found: "XD"
        from (irb):30:in `fetch'
        from (irb):30
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>> passwords.key? "XD"
=> false
>> passwords.fetch("XD", "no such key")
=> "no such key"
>> passwords.fetch("XD") { nil }

=> nil
>> passwords.value? 123456
=> true
>>


在上例中可以看到,fetch方法可以指定區塊,在指定的鍵不存在時,區塊的傳回值會是fetch的傳回值。

可以使用Hash.new來建立雜湊物件,如果呼叫時有傳入引數,則指定的鍵不存在時,會傳回Hash.new時傳入的引數,如果呼叫Hash.new時沒有傳入引數,指定的鍵不存在時會傳回nil。例如:
>> passwords = Hash.new
=> {}
>> passwords["XD"]
=> nil
>> passwords = Hash.new(0)
=> {}
>> passwords["XD"]
=> 0
>> passwords = Hash.new { |hash, key|
?>     "no such key #{key}"
>> }
=> {}
>> passwords["XD"]
=> "no such key XD"
>>


可以看到,Hash.new時也可以指定區塊,區塊的傳回值就會是在指定的鍵不存在時的傳回值。

想要知道雜湊長度,可以使用sizelength方法,想要知道雜湊是否為空,可以使用empty?方法,想要取得雜湊中所有鍵,可以使用keys方法,這會以陣列傳回所有鍵,想要取得雜湊中所有值,可以使用values方法,這會以陣列傳回雜湊中所有值,使用to_a,則將鍵值以二維陣列傳回:
>> passwords = {"Justin" => 123456, "caterpillar" => 933933}
=> {"Justin"=>123456, "caterpillar"=>933933}
>> passwords.length
=> 2
>> passwords.keys
=> ["Justin", "caterpillar"]
>> passwords.values
=> [123456, 933933]
>> passwords.to_a
=> [["Justin", 123456], ["caterpillar", 933933]]
>>


想要逐一取得雜湊中的鍵,可以使用each_key方法,想要逐一取得雜湊中的值,可以使用each_value方法,想要逐一取得鍵與值,可以使用each方法:
>> passwords.each_key do |key|
?>     puts key
>> end
Justin
caterpillar
=> {"Justin"=>123456, "caterpillar"=>933933}
>> passwords.each_value do |val|
?>     puts val
>> end
123456
933933
=> {"Justin"=>123456, "caterpillar"=>933933}
>> passwords.each do |key, val|
?>     puts "#{key}-#{val}"
>> end
Justin-123456
caterpillar-933933
=> {"Justin"=>123456, "caterpillar"=>933933}
>>


之後會談到,建立雜湊時,任何實例 可以作為鍵,但建議重新定義eq?與hash方法,而且最好使用不可變動物件作為鍵,先前談 符號型態 時說明過,Symbol實例為不可變動,且擁有唯一性,因此經常用來作為雜湊的鍵物件。例如:
>> passwords = {:Justin => 123456, :caterpillar => 933933}
=> {:Justin=>123456, :caterpillar=>933933}
>> passwords[:Justin]
=> 123456
>> passwords[:caterpillar]
=> 933933
>>


因為Symbol實例作為鍵很常用,在Ruby1.9之後,還可以寫得更簡潔,作用與上例相同:
>> passwords = {Justin: 123456, caterpillar: 933933}
=> {:Justin=>123456, :caterpillar=>933933}
>> passwords[:Justin]
=> 123456
>> passwords[:caterpillar]
=> 933933
>>


在Ruby 1.9之後,雜湊是有序的,鍵的順序就是安插雜湊的順序,也會使用索引記錄。例如:
>> passwords = {Justin: 123456, caterpillar: 933933, Monica: 987654}
=> {:Justin=>123456, :caterpillar=>933933, :Monica=>987654}
>> passwords.each_with_index do |kv, index|
?>     puts "#{index} - #{kv}"
>> end
0 - [:Justin, 123456]
1 - [:caterpillar, 933933]
2 - [:Monica, 987654]
=> {:Justin=>123456, :caterpillar=>933933, :Monica=>987654}
>> passwords.each_with_index do |(key, value), index|
?>     puts "#{index} - #{key}, #{value}"
>> end
0 - Justin, 123456
1 - caterpillar, 933933
2 - Monica, 987654
=> {:Justin=>123456, :caterpillar=>933933, :Monica=>987654}
>>


each_with_index方法的第一個區塊參數接受陣列物件,當中包括每次迭代的鍵與值物件,第二個區塊參數則是索引。上例中第二次使用each_with_index時,使用括號(key, value),這會將陣列中第一個索引元素指定給key,第二個索引元素指定給key,利用的是 陣列型態 中談過的特性。