iT邦幫忙

2021 iThome 鐵人賽

DAY 1
0
自我挑戰組

初級紅寶石魔法師心得分享。系列 第 1

D-29. 常數, 變數, 符號, 數字 && Leetcode : Power_of

資料型態

多數程式語言的學習第一步常為瞭解資料型態,畢竟分不清楚資料的型態的話,就不可能對資料做出正確處理或判斷,以比喻來說,買股票時,明知道電子股會漲,但是卻買進保護傘公司的股票,以為保護傘公司是電子科技股,結果是搞生化的!?

Ruby的設計風格

多數文章資料都會直接說一句Ruby裡幾乎所有東西都為物件,造成這點的原因是,Ruby在設計上已經將資料的特性與方法包裝後,組成各種class,所謂的東西都是指class產生的實體。

BasicObject為所有常用類別的頂端(但Class的頂端是Module),再以duck typing設計風格,將資料特性分組好,給予我們想要執行的方法包裝好後,再給予一個名字(標籤,常數),就成了許多的新class。

物件即為class的實體化,所以物件本身就包含了特性與方法,所以才可以操作物件,因此Ruby內所有東西都為物件

不是所有物件導向設計的程式語言都是如此設計,但Ruby這樣設計,且物件導向的很徹底。

wiki--物件導向程式設計
文章盡量導向中文資料,能力許可下還是看英文資料較好。

常見資料類別

Ruby中有個語法,在資料後面加上.class,可以查資料的類別。

2.7.3 :020 > :a1234.class
 => Symbol
2.7.3 :021 > 1234.class
 => Integer
2.7.3 :022 > "1234".class
 => String  #有""或''的就為字串。
2.7.3 :023 > [1, 2, 3, 4].class
 => Array
2.7.3 :024 > (1..4).class
 => Range
2.7.3 :025 > {:a => 1, "b" => 2, c: 3}.class
 => Hash

另外可以用.methods對類別產生的實體查詢本身有哪些方法。(方法等於怎麼操作這些資料)

2.7.3 :022 > new_array = Array.new
 => []
2.7.3 :023 > new_array.methods
 => [:to_h, :include?, :&, :*, :+, :-, :at, :fetch, :last, :union, :difference, :intersection, :push, :append, :pop, :shift, :unshift, :each_index, :join, :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :filter!, :keep_if, :values_at, :delete_at,
 略....]
#太多了
2.7.3 :024 > new_array.methods.size
 => 192
#192種.
2.7.3 :067 > Array.methods.size
 => 114
#補充:Array原生只有114種方法,new出來的有多78種。可以兩者相減看看多哪些方法
Array.methods - new_array.methods

較特殊的。

2.7.3 :024 > true.class
 => TrueClass
2.7.3 :025 > false.class
 => FalseClass
2.7.3 :026 > nil.class
 => NilClass  #null或其他語言可能拼法不同。

布林值,Ruby沒有這種型別,但是有給予類別,在我個人學習後會比較讓自己去記得Ruby只有類別,沒有型別。
但是資料的確是都有自己的型態沒錯。(記憶體儲存方式)
nil就是空的,會去記,Ruby為了讓你看到空白,所以讓你看到nil

2.7.3 :003 > nil.to_s
 => ""
#真的如果有新手路過看到這個還看不懂,請先略過之後都會說明。

當然Ruby中不只這六種類別,這六種為比較常見的Ruby資料類別而已,初學會以這幾種出發。除了符號這類別可能比較陌生,還有Hash在Ruby叫雜湊外,其他的資料處理方式都與其他程式大同小異。認識資料類別最大目的為,怎麼處理資料,Ruby雖然為強型別語言,但個類別間有很多方法做轉換,甚至有很多同名方法,初學以能越快速掌握越好。而由於網路上大神們的資料已經夠詳細,我將會直接以解題做分享。


變數、常數

為何需要變數或常數?

Ruby是物件導向程式設計的語言。
無論瞭不瞭解OOP,先知道如果需要處理物件,以變數來指向,會比較便利。
變數與常數簡單一點來想就是,只是一個標籤(名字),拿來指向一個物件,物件於Ruby多指類別的實例,也就是實體,最簡單的實體就是基礎的資料,指向完成後,變數成為了實體(物件)的名字,我們可以將變數拿來操作,不用重複輸入物件(實體)。

怎麼指向?

例如:x = 123
看起來像x這個變數等於123
事實上x這變數指向123
=是個指向方法,不是等於。

例如:

2.7.3 :091 > num = 202120212021
 => 202120212021
2.7.3 :092 > num / 2021
 => 100010001
2.7.3 :093 > num * 2021
 => 408484948494441
2.7.3 :094 > num - 2021
 => 202120210000

以及以後會常看到的

2.7.3 :099 > num = 10
 => 10
2.7.3 :100 > num
 => 10
2.7.3 :101 > num = num - 5
 => 5
2.7.3 :102 > num
 => 5
2.7.3 :103 > num = num * 5
 => 25
2.7.3 :104 > num
 => 25
#賦予運算,下面會稍微提到為何可以如此操作。

變數與常數差異?

變數為開頭小寫英文的數字加組合,如abca123a1b1aAaa,除了_不要有計算符號於內,如a+ca@ax123^這些都會造成錯誤。

常數為開頭大寫英文的數字加組合,其餘與變數相同,如AbcA_BC
因此於Ruby,除開頭大小寫外,使用Ruby者多以常數指向不輕易變動之資料,若要變動則會有警告提示(而已),所以類別與模組強制使用常數來命名。

2.7.3 :005 > num = 1
 => 1
2.7.3 :006 > num = 2
 => 2
2.7.3 :007 > num = 3
 => 3
2.7.3 :008 > Num = 1
 => 1
2.7.3 :009 > Num = 2
(irb):9: warning: already initialized constant Num
(irb):8: warning: previous definition of Num was here
 => 2
#對,就警告而已,我們是大人了,不要做被警告的事就好。

2.7.3 :012 > def Add(num1, num2)
2.7.3 :013 >   num1 + num2
2.7.3 :014 > end
 => :Add   #方法用變數,這是錯誤示範,強調Ruby的風格較自由,但Ruby使用者不會這麼做。

2.7.3 :015 > class error
2.7.3 :016 >   p "錯誤"
2.7.3 :017 > end
SyntaxError ((irb):15: class/module name must be CONSTANT)
class error
      ^~~~~  #沒有例外
#類別只能用常數。

命名原則

保持可閱讀性,寧可越詳細越好,也盡量不要有xaxy、這種無意義的魔法編碼。
請讓一年後的自己還知道自己了寫什麼
使用者多以蛇式命名、first_number

保留變數:很多,記會噴錯就代表不能用,例如不可能會有nil = 123if = 123

變數種類

會於進入Rails前說明。

請記得變數與常數未指向任何實體前,沒有實際上的意義。


符號與字串差別,符號與變數差別?

我們先了解怎麼用。

什麼是符號?
符號指:加上變數。變數前面掛上:就會成為符號。

2.7.3 :019 > :abc
 => :abc
2.7.3 :010 > :acb.class
 => Symbol

#不是:是符號,而是:abc是一個符號。
#不是指+,-,*,%這些已經被包裝成方法的運算式,也不是指@, #, $這些。

符號常見於Hash中當做Key指向Value,{:a => 1},或將方法名稱標記,等於是一個固定住的物件。

2.7.3 :001 > def some_method
2.7.3 :002 >   p "do something"
2.7.3 :003 > end
 => :some_method
# 運用到Rails上會看到下面類似使用方式。
after_save :some_method
# 在實體存擋後執行一個方法。

#我們可以隨意將變數隨意拿來使用
2.7.3 :004 > some_method = 123
 => 123
2.7.3 :005 > some_method = 1234
 => 1234
#但符號不能
2.7.3 :006 > :some_method = 123
SyntaxError ((irb):6: syntax error, unexpected '=', expecting end-of-input)
:some_method = 123
             ^
#即使變數一直改指定,剛剛def的方法不會受影響。
2.7.3 :007 > some_method()
"do_something"
 => "do_something"

some_method這串英文只是變數,可以指向任何資料,也可以當方法的名稱。
:some_method等於是有個方法(物件)出現了,給他除了變數外,加固給他一個特別的名字。

Hash中,字串也可以當Key。

2.7.3 :025 > {:a => 1, "b" => 2, c: 3}.class
 => Hash
#上面寫法錯誤示範,下篇介紹Hash會說明。

但符號的記憶體位置是固定的,字串不是。

2.7.3 :014 > :some_method.object_id
 => 2041948
2.7.3 :015 > :some_method.object_id
 => 2041948
2.7.3 :016 > "some_method".object_id
 => 180
2.7.3 :017 > "some_method".object_id
 => 200
2.7.3 :018 > "some_method".object_id
 => 220
2.7.3 :019 > "some_method".object_id
#也所以Rails還是常見。
after_save :some_method
#下面也是可以。
after_save "some_method"

整理

符號,字串,變數三者是不同的。
符號,字串為類別的一種,:symbol"string"則已經是實體(物件),變數只是指向物件(實體)的標籤。
符號,字串都可以當KEY指向物件,而由於記憶體固定,處理符號會比處理字串稍快,但字串本身具有方法就多,選用上可視狀況更改。

回頭看到上面的 num = num + 1

符號與字串就不能這樣操作,在指向(=)這個方法前面只能是變數。
那 = 這方法是前面先執行還是後面先執行?

2.7.3 :002 > x.class
NameError (undefined local variable or method `x' for main:Object)
#x是變數,不是任何類別

2.7.3 :003 > x = z
NameError (undefined local variable or method `z' for main:Object)
#z是變數,但沒指向任何物件。

2.7.3 :004 > x.class
 => NilClass
#但是剛剛的x已經變成一種nil類別的。但還是沒有意義喔nil於Ruby就是nil。

2.7.3 :005 > z.class
NameError (undefined local variable or method `z' for main:Object)
#z卻沒有

我會先回答,= 將前面變數預設成nilcalss,= 後面是運算式(或方法或物件)的回傳值。
答非所問!?


數字

2.7.3 :019 > 1.class
 => Integer
2.7.3 :020 > 0101.class
 => Integer  #2進制
2.7.3 :030 > "32".to_i.class #=> 32
 => Integer
2.7.3 :025 > x = 50
 => 50
2.7.3 :026 > x.class
 => Integer #變數指向什麼資料,變數則表示什麼類別。
2.7.3 :027 > arr = [1, 2, 4, 5]
 => [1, 2, 4, 5]
2.7.3 :028 > y = arr.size
 => 4
2.7.3 :029 > y.class
 => Integer
 2.7.3 :031 > (x - y).class
 => Integer #運算式,方法結果為數字,類別則為數字。

處理數字類別時,理所當然的對數學越了解越吃香,但數學不強,至少要認識基本運算符號到底求的是什麼。

2 * 3 #=>6 ,一個*是乘法
2 ** 3 #=>8 ,兩個**是次方
10 / 2 #=>5 ,/ 是求商
10 % 2 #=>0 ,% 是求餘
#賦予運算 +=, /=, *=等
#判斷 ==, !=, <, >等。

數字的兄弟:浮點數

2.7.3 :032 > 1.0.class
 => Float
2.7.3 :033 > 1.0342342343.class
 => Float
2.7.3 :034 > y = 7 / 3
 => 2
2.7.3 :035 > y.class
 => Integer
2.7.3 :036 > y = 7 / 3.0
 => 2.3333333333333335
2.7.3 :037 > y.class
 => Float

初期最重要一點,Integer與Float運算結果為Float。

第一天的Leetcode題:Power of Two & Power of Three & Power of Four

這三題剛好都可以用單純數學來解,所以一起說了避免我之後偷懶拿來混天數
另外預防針:由於菜鳥,時間空間複雜度我不會去討論,能解優先。

題目連結Power of Two:https://leetcode.com/problems/power-of-two/
題目連結Power of Three:https://leetcode.com/problems/power-of-three/
題目連結:Power of Four:https://leetcode.com/problems/power-of-four/

三題分別求Input是否為2, 3, 4的次方數。
三題都可以跑迴圈

#0次方都是等於1,所以1一定對。
return true if n == 1
#設定自乘次數起始值
power_number = 1 #設1是因為0次方是1
#Input都一定是2或3或4,自己乘自己N次後會變成的數。請記得我們在三題一起解..
while power_number < n
  power_number *= 2 #或3 , 4
end
  power_number == n

整理一下

def is_power_of_?(n) # ? = two, three, four
  return true if n == 1
  power_number = 1 #設1是因為0次方是1

  while power_number < n
    power_number *= ? #?請自行換2,3,4
  end
  power_number == n
end

而數學比較好的人,可能會了解,2或3的(n次方數大的)除以2或3的(n次方數小的),一定沒有餘數這件事。

2.7.3 :036 > (2**100)%(2**50)
 => 0
2.7.3 :037 > (2**100)%(2**99)
 => 0
2.7.3 :038 > (2**100)%(2**4)
 => 0
2.7.3 :039 > (2**100)%(2**0)
 => 0

所以可以更快的想到另一種解答。

  #2的,為何用2的32次方,因為題目提示有說 n < 2**32
  n <= 0 ? false : (2**32 % n == 0)
  #3的,1162261467是3的19次方,20次方就超過 2**32了
  n > 0 && 1162261467 % n == 0

2用三元運算子寫,3用兩個判斷句合併,寫法不同目的相同。
另外,4的確也符合(大的N次方)%(小的N次方)是餘零這件事,但是由於4 = 2*2這件事,所以不會直接拿來解,但可以利用

(4**n - 1) % 3 == 0

這個邏輯來解喔。

本日結束,明日會用其他例題說明字串,範圍,陣列,雜湊。


整理今天提到。
1.變數與常數差異。
2.符號、變數、字串三者差異。
3.資料基本型態:Integer
4.leetcode:power_of_two..four


下一篇
D-28.鴨子型別, 字串, 陣列, 範圍, 雜湊
系列文
初級紅寶石魔法師心得分享。30

尚未有邦友留言

立即登入留言