iT邦幫忙

DAY 11
1

Ruby女孩:10萬.times { puts "為什麼?" }系列 第 11

Ruby女孩(11):雜湊雜湊雜湊,重要的事情會說三次!

啊,十天後,我們來到了書的第70頁(整本書有455頁),其實進度有點緩慢Orz不過還是秉持著第8天的小語:
『Keep moving forward. One step at a time.』,不急,只要我繼續往前進,一次一步慢慢扎穩就好!

好的,來談談Ruby中非常重要的一環:雜湊(Hash)

※什麼是雜湊?(p.70)

『雜湊(Hash)是一種資料結構,其中保存了一組稱為鍵(key)的物件,而且每個鍵都會被關聯到一個值(value)。雜湊也被稱為對映表,因為它會將鍵對應至值。雜湊有時會被稱為關聯陣列(associative array),因為每個鍵都會被關聯到一個值,所以可將它視為以任何物件(而非整數)為索引值的陣列。』

上面的文字完全來自於書本中,雖然讀起來有點跳針XD,但你不得不說,重要的事情會被說三次,你看到上面這段什麼東西出現三次了嗎XD?

『每個鍵都會被關聯到一個值』!!!
『因為它會將鍵對應至值』!!!
『因為每個鍵都會被關聯到一個值』!!!

是的!不管你要叫它什麼名字,它有一個特大重點:在雜湊中,有一個鍵(key)會對到一個值(value)!
馬上來看個例子:

rank = { "非常喜歡" => 5, "很喜歡" => 4, "沒感覺" => 3, "很討厭" => 2, "非常討厭" =>1 }

上面這個雜湊是以大括號 { } 包起來,其中,鍵(key)指的是"非常喜歡"、"很喜歡"、"沒感覺"、"很討厭"、"非常討厭",而值(value)指的是5、4、3、2、1。

以下三種寫法都是雜湊的寫法:

rank1 = { "非常喜歡" => 5, "很喜歡" => 4, "沒感覺" => 3, "很討厭" => 2, "非常討厭" =>1 }
rank2 = { :非常喜歡 => 5, :很喜歡 => 4, :沒感覺 => 3, :很討厭 => 2, :非常討厭 =>1 }
rank3 = { 非常喜歡: 5, 很喜歡: 4, 沒感覺: 3, 很討厭: 2, 非常討厭: 1 }

把上面這三行拿去irb執行後可以看到:

rank1:
=> {"非常喜歡"=>5, "很喜歡"=>4, "沒感覺"=>3, "很討厭"=>2, "非常討厭"=>1}

rank2:
=> {:非常喜歡=>5, :很喜歡=>4, :沒感覺=>3, :很討厭=>2, :非常討厭=>1}

rank3:
=> {:非常喜歡=>5, :很喜歡=>4, :沒感覺=>3, :很討厭=>2, :非常討厭=>1}

有注意到嗎?其實rank2與rank3執行結果是完全相同的!rank3的寫法是ruby1.9之後才支援的寫法,這種寫法比較簡潔方便。但更要注意的是, "非常喜歡" :非常喜歡 是完全不同的兩種key喔!以下來證明兩種完全不同(數學老師上身):

#如果我們想把rank2中的:非常喜歡的值從5改成100,我們可以這樣寫:
rank2[:非常喜歡] = 100

#此時rank2變成:
=> {:非常喜歡=>100, :很喜歡=>4, :沒感覺=>3, :很討厭=>2, :非常討厭=>1}

#但如果我的改法是這樣寫:
rank2["非常喜歡"] = 555

#此時rank2變成:
=> {:非常喜歡=>100, :很喜歡=>4, :沒感覺=>3, :很討厭=>2, :非常討厭=>1, "非常喜歡"=>555}

如果它找得到相同的key,會直接改掉原本key的值,但是因為他找不到相同的key,所以就在最後面新增了一組key和value。

由上述可知"非常喜歡"與:非常喜歡是完全不同的兩種key,得證XD!

事實上,如果你要比較兩個雜湊的鍵到底有沒有一樣,也可以使用 .eql? 這個方法,例如:

a = {:love =>5, :hate =>0}  => {:love=>5, :hate=>0}
b = {"love" =>5, "hate" =>0}  => {"love"=>5, "hate"=>0}

a.eql?b  => false

再次證明這是不一樣的雜湊喔!

其實有個更重要的議題是,字串 " " 跟符號 : 的差異是什麼?好像不太能用一兩句話說清楚,這個書中在本章節最後面有提,到時候會一併說明!

=================================================

第十一天,

Believe in yourself.

加油!


上一篇
Ruby女孩(10):["十年","好姐妹","陣列萬歲"]
下一篇
Ruby女孩(12):Range讓我知道..我是草莓族,Ruby不是QQ
系列文
Ruby女孩:10萬.times { puts "為什麼?" }30
0
kevin3372000
iT邦新手 3 級 ‧ 2014-10-11 19:19:06

"hello" => 這是 string
:hello => 這是 symbol

兩者之間的差異在於:

在 Ruby 當中每一個 string 都是存放在不同的記憶體位置,即使內容完全一樣也是。例如:

"hello".object_id
=> 70248908847880
"hello".object_id
=> 70248908816100

(兩者的 object id 不同,意味著兩個 string 分別置於不同的記憶體位址)

然而當你在 Ruby 宣告一個 symbol 時,一個 symbol 只會占用一個記憶體位址,也就是說兩個一樣的 symbol ,記憶體位址都是一樣的,不會浪費額外空間存一樣的東西。

因此如果你在 irb 測試就會看到類似以下的結果:

2.0.0-p353 :003 > :hello.object_id
=> 538888
2.0.0-p353 :004 > :hello.object_id
=> 538888

0
otiann
iT邦新手 2 級 ‧ 2014-10-11 21:06:35

@Kevin謝謝你的補充解釋!而且講得超清楚!!感謝感謝!!!

我也要把書上提到相關的部分補充上來,雖然Ruby支援字串(string)跟符號(symbol)都能當做Key,但由於字串是可變動的,一旦key被改變時,連帶他在記憶體的位置(書上指的是雜湊碼)也會被改變,導致存放雜湊的雜湊表會遭到破壞。因此較建議以symbol(在記憶體的位置為唯一)作為雜湊的key,才能正確運作。

0
kevin3372000
iT邦新手 3 級 ‧ 2014-10-11 22:12:56

補充一點點「資料結構」的概念:

不管是哪一個程式語言,一定都有 array (陣列),事實上 array 就是一種 Data Sructure 。Array 以 low level 的角度來看,實際上它就是連續的記憶體位址。

array 雖然方便,但是在某些情境下事實上使用 array 是不太適合的,例如:你有大量資料,而這些資料是存在一個 array 裡面,那麼假設我們要在 array[3] 的位置新增一筆資料,就必須要把「原來 array[3]的值」以及「其後面所有的元素」都往後挪一格,很明顯這樣的效能是非常低落的。

因此如果想要程式的效能很好,除了演算法要選對,資料結構也是非常重要的因素。

在 Ruby 裡面已經內建 Hash 這種 Data Structure ,因此開發者可以輕易地使用。不過如果換成 C 這種較 low level 的程式語言,這些東西就得自己實作了。

基本上寫 Web 不太會用到這些東西啦 XD 但是我覺得這是非常重要的概念,所以特別補充一下。

0
otiann
iT邦新手 2 級 ‧ 2014-10-12 23:26:11

(y) Hash真是太方便了!

深深覺得自己對程式的語言還有很大的不足,所以在解釋時都不能說明的很清楚XD",從Kevin的文章中總是能得到很多幫助啊!都是扎實而且非常清楚的!!哈哈即使這些可能用不到,但卻是很重要的觀念呢!謝謝Kevin!!

我要留言

立即登入留言