程式設計基礎練習
1. 前言準備
這堂課將練習編程的基礎邏輯,包括:
- 輸入、處理、輸出
- 基本算術
- 控制流程
- 函式方法
- 循環
- 陣列 Array
- 雜湊 Hash
- 物件 Object
- 檔案 File
難度大約是電腦本科生大一程度,也是程序員一定會的基本題。
請在 Github 上 Fork 這個專案 https://github.com/ihower/programming-exercise,然後 git clone 回去:
git clone [email protected]:your_name/programming-exercise.git
cd programming-exercise.git
其中每個 .rb
檔案就是一個小題目需要完成,用 ruby 檔名
就會執行,例如:
ruby 01-hello.rb
就會執行第一個題目。請完成一題就 commit 一次,最後送 Pull Request 交作業。
題目看起來很多,但是其實每一題的答案只是幾行代碼而已,不用想太複雜。
2. 輸入、處理、輸出
題目 1
輸入名字,輸出 “Hello, 名字”
成功畫面:
題目 2
交換變數 a
和變數 b
的值
提示說明
標準螢幕輸出(STDOUT)
puts
會輸出變數在螢幕上,並且有換行print
也會輸出變數在螢幕,不會換行
標準螢幕輸入(STDIN)
gets
可以從鍵盤拿到輸入的值。
什麽是變數?
讓電腦(記憶體)記住一個值(value),就像一個箱子📦 =
是賦值運算符(assignment operator),是指派右邊的值到左邊的變數
在 Ruby 中,一律用小寫開頭命名變數,並且習慣用 _
底線來分隔單字,例如 your_name
。
字串 String
"用雙引號包起來"
'或是用單引號'
"如果裡面有'單引號',那就要用雙引號包起來"
'如果裡面有"雙引號",那就要用單引號包起來'
"如果你堅持雙引號裡面要有雙引號,那你得寫成 \" 做逸出"
字串串接
用 +
的,例如 "a" + "b"
字串內嵌
用 #{}
的語法可以將變數內嵌在字串中
例如 "This is #{a}"
如何註解?
在 Ruby 中用 #
註解。#
後面的字都不會執行
irb 互動式 Ruby 環境
執行 irb
可以進入 Ruby 的互動式環境,可以快速地練習進行語法實驗
3. 基本算術
題目 3
輸入直角三角形的底和高,輸出三角形的面積(底乘高除二)
題目 4
輸入有多少片比薩餅和多少人,輸出每人可以分到幾片,以及剩下幾片
提示說明
什麽是數據類型?
每個值都屬於一個數據類型,例如有:
- 字串 String
- 整數 Integer (不可以有小數)
- 浮點數 Float (可以存放小數)
- 陣列 Array
- 雜湊 Hash
整數和浮點數
- 沒有小數點的就是整數,例如
123
- 有小數點的就是浮點數,例如
123.0
或12.3
有哪些基本算術?
+
加-
減*
乘/
除%
餘數,例如20 % 3
是2
註意,整數除整數還是整數。只有浮點數運算的結果才會是浮點數。
例如 10/4
會是 2
。要 10.0 / 4
才是 2.5
型別轉換 (Type Conversion)
字串和數字是不能直接相加的,會出現 TypeError 的錯誤,需要先做型別轉換:
- 透過
to_i
可以將字串轉成整數,例如"123".to_i
變成123
- 透過
to_f
可以將整數轉乘浮點數,例如123.to_f
變成123.0
- 透過
to_s
可以轉成字串,例如123.to_s
變成"123"
注意,在 gets 中,拿到的是「字串」,即使你輸入的是數字。所以如我要做數字計算,記得先做型別轉換。
在 Rails controller 中,params 的值也都是字串。
浮點數常用方法
四捨五入 round
1.4.round #=> 1
1.5.round #=> 2
1.6.round #=> 2
(-1.5).round #=> -2
無條件進制 ceil
1.2.ceil #=> 2
2.0.ceil #=> 2
(-1.2).ceil #=> -1
(-2.0).ceil #=> -2
無條件捨去 floor
1.2.floor #=> 1
2.0.floor #=> 2
(-1.2).floor #=> -2
(-2.0).floor #=> -2
更多請參考 Ruby Float API
4. 控制流程
題目 5
輸入體重和身高,輸出身體質量指數(BMI)和建議文字
BMI 公式為 bmi = ( 體重 / (身高x身高) ),單位是公斤和公尺
- 如果 BMI < 18.5,顯示過輕
- 如果 BMI >= 24,顯示過重
- 如果 BMI 介於 18.5 ~ 24,顯示正常
題目 6
輸入一個數字 x
,請判斷是否正數、零或負數,以及是不是偶數
題目 7
輸入數字 x
, y
, z
,請根據以下的判斷輸出結果
- 當 x < 0 輸出 “A”
- 當 x > 0
- 當 y > 0
- 當 z > 0 輸出 “B”
- 當 z < 0 輸出 “C”
- 當 y < 0
- 當 z > 0 輸出 “D”
- 當 z < 0 輸出 “E”
- 當 y > 0
題目 8
輸入數字 x
, y
, z
,請輸出三個數中最大的數
提示說明
布林 Boolean 數據類型
布林 Boolean 數據類型只有兩種值: true
或 false
關系運算子
以下這些運算子,都會回傳 Boolean 值,也就是 true
或 false
==
!=
<
>
<=
>=
例如 "123" == "123"
會回傳 true
,123 > 555
會回傳 false
控制流程(Control Flow)
透過 Boolean 條件,就可以決定程序怎麽執行
if 9 > 3
# 這段會執行
else
# 這段不會執行
end
更多條件的話:
if a > b
# ...
elsif a == b
# ...
else
# ...
end
邏輯運算子
&&
且
- 當
a
和b
都是true
時,a && b
回傳true
- 當
a
或b
任一個是false
時,a && b
回傳false
||
或
- 當
a
或b
任一個是true
時,a || b
回傳true
- 當
a
和b
都是false
時,a || b
回傳false
!
相反
如果 a
是 true
,那 !a
就是 false
。反之亦然。
透過 &&
和 ||
,就可以結合不同條件:
if ( 9 > 3 ) && ( 6 == 6)
# ...
elsif ( 2 > 1 ) || ( 5 < 1 )
# ...
end
Boolean 轉型
條件不需要一定要轉成 Boolean 型態,在 Ruby 之中只要不是 false
或 nil
,都會自動判斷成 true
例如:
if "foobar"
# 會執行
end
if 123
# 會執行
end
if 0
# 會執行
end
if ""
# 會執行
end
if []
# 會執行
end
if nil
# 不會執行
end
5. 方法 Method
題目 9
將題目 3 計算直角三角形面積,改成調用方法
題目 10
將題目 8 找出三個數中最大的數,改成調用方法
提示說明
一些需要重復被執行的代碼,可以透過定義函式包裝起來,方便之後繼續調用
有些程式語言的術語用 Function 函式,在 Ruby 中則習慣稱之為 Method 方法。
如何定義方法和調用
用 def
def hello
puts "Hello"
end
hello() # 這樣會調用 hello 方法
hello # 在 Ruby 語言中 () 可以省略
如何帶入參數
def hello(name)
puts "Hello, #{name}"
end
hello("ihower") # 這樣會調用 hello 方法
hello "ihower" # 在 Ruby 語言中 () 可以省略
回傳值
def get_hello(name)
return "Hello, #{name}"
end
str = get_hello("ihower")
puts str
在方法中用 return
返回一個值,讓我們可以把它存進一個變數,在後面的程序來使用。
如果沒有寫 return
,該方法的最後一行的值會自動被返回。例如上述程式的 return
可以省略:
def get_hello(name)
"Hello, #{name}"
end
6. 循環 Loop
題目 11
輸出 1 到 100 之間,所有 7 的倍數。
題目 12
求 1~100 所有偶數的和
題目 13
輸入一個數字 N,輸出 N * N 乘法表,例如輸入 12,輸出
0 x 0 = 0
0 x 1 = 0
......
12 x 11 = 132
12 x 12 = 144
題目 14
輸入一個數字 N,請檢查是不是質數
提示:從 2 開始到 N/2 不斷去除這個數字,如果可以整除就表示不是質數
題目 15
猜數字游戲:程序會先產生一個隨機數,然後用戶開始猜這個數字。
程序會針對猜的數字回答太高、太低或猜中,猜中後程序就會終止。
提示說明
什麽是循環?
就是可以重復執行某段程式碼,直到滿足某個條件。
x = 10
while x <= 10
puts x
x = x + 1
end
這個 while
就會一直循環,直到 x 超過 10 不滿足條件,才會離開循環。
注意,如果 while
的終止條件沒有滿足,會變成無窮循環,程序就不會終止了。
提前中斷
在 while
循環中,用 break
關鍵字,會提前中斷循環
7. 陣列 Array
題目 16
給定一陣列內含數字,輸出最大值
題目 17
使用者不斷輸入數字存進陣列 Array,最後輸出總和、平均、最大值、最小值
注意:如果沒有輸入任何東西直接按 Enter,gets
仍會讀到一個換行符號,這是一個螢幕不可見的字符,在字串中用 "\n"
表示。
題目 18
輸入數字 N,建構一個陣列有 N 的元素,內容是 0, 1, 4, 9, 16, 25…… 每個元素是該索引的平方。
例如 N = 1,則陣列是 [0] 例如 N = 3,則陣列是 [0,1,4]
題目 19
給定一陣列內含數字,輸出另一個陣列只包含偶數
提示: 新建立一個空陣列,然後走訪本來的陣列檢查每一個元素,如果符合條件就塞進(push)進新的陣列。
題目 20
承上題,請排序並去除重復的數字
提示:可用 arr.sort
健行排序,以及 arr.uniq
去除重復
題目 21
Ruby 的 Array 陣列是內建了
.sort
方法可排序,我們這裡練習自行實作一個排序算法。
給定一陣列內含數字,請實作選擇排序法進行排序。
假設陣列有N個元素,先從第一個元素走訪到最後一個,找到最小的那一個交換到第一個位置。
接著從第二個元素走訪到最後一個,找到最小的元素,交換到第二個位置。以此類推,最後就會得到一個從小到大的陣列。
題目 22
給定一陣列內含數字,請輸出 0~9 中不見的數字。例如 arr = [2,2,1,5,8,4]
,輸出 [0,3,6,7,9]
提示說明
什麽是陣列?
- 一個有順序的容器,用數字當作索引。
- 索引從 0 開始
- 原則上裡面的元素,數據類型最好都是一樣的,例如都存整數,或是都存字串。
以下就是一個陣列,用中括號前後包住,用逗號分隔:
array = [5,1,2,3,5]
陣列裡面還可以放陣列,這樣會變成二維陣列:
array = [
[1,2,3],
[4,5,6],
[7,8,9]
]
array[0][0] # 這是 1
array[0][1] # 這是 2
array[2][2] # 這是 9
如何走訪陣列?
用 for
方法:
for i in array
puts i
end
在 Ruby 中更習慣用 each
方法:
array.each do |i|
puts i
end
如果走訪時,需要索引值,可以改用 each_with_index
方法:
array.each_with_index do |i, j|
puts i
puts j # j 從 0 開始數
end
如何操作陣列?
array.size
會回傳陣列長度
array[1]
會讀取第二個元素
array[1] = 999
會更改第二的元素的值
array[99999]
讀取一個不存在的值,會回傳 nil
array[0]
或 array.first
是陣列的第一個元素
array[-1]
或 array.last
是陣列的最後一個元素
array.push(999)
或 array << 999
會新增一個元素 999 到陣列的最後面
array.unshift(999)
會新增一個元素 999 到陣列的最前面
array.delete_at(i)
會刪除索引值在 i 的元素
更多 Ruby 的 Array 方法請參考 Ruby Array API
字串與陣列
程式語言內部實作字串的方式,就是將一個一個字符用陣列連結起來。這就是為什麽字串也可以用數字索引操作:
str = "ABCDEFG"
str[0] # 得到 "A"
str[1] = "x"
str # 變成 "AxCDEFG"
str.split("") # 用 "" 拆開字串,得到陣列 ["A", "B", "C", "D", "E", "F", "G"]
["x", "y", "z"].join(" ") # 用 " " 串接成字串,得到 "x y z"
8. 雜湊 Hash
題目 23
給定一雜湊 Hash,輸出有最大值(value)的鍵(key)
題目 24
給定一雜湊 Hash,輸出值(value)是偶數的鍵(keys)
注意,答案是一個陣列
題目 25
計算一個陣列中各個元素的出現頻率
題目 26
給定一個雜湊 Hash,請根據指定的鍵值進行過濾和排序
提示說明
什麽是雜湊 Hash?
用鍵(key)當作索引的容器,例如
h = { "a" => 123, "b" => 456 }
h["a"]
就是 123
h["b"]
就是 456
h["qweqkleklwqen"]
如果讀取一個不存在的key,結果會是 nil
h["new_key"] = 123
如果本來沒有這個 key,就會直接新增一組 key-value
如何走訪雜湊 Hash?
h.each do |key, value|
puts key
puts value
end
常用方法
h.keys
會回傳一個陣列包括所有 keys
h.values
會回傳一個陣列包括所有 values
h.merge(h2)
會合並雜湊 h2 到雜湊 h
更多 Ruby 的 Hash 方法請參考 Ruby Hash API
9. 物件 Object
題目 27
請自訂一個 Person 物件,屬性有 first_name
, last_name
,然後定義一個方法是 greet
會輸出 "Hi, <first_name> <last_name>"
提示說明
什麽是物件?
物件(Object)也是一種數據類型,這種數據除了擁有屬性,也有方法可以調用。
在 Ruby 之中,其實每種數據類型,例如 String、Integer、Float、Array、Hash 等等,也都是物件(Object)。
例如字串的 size
方法和 split
方法:
"abc".size
會回傳 3
"a,b,c,d".split(",")
會回傳陣列 ["a", "b", "c", "d"]
其中 .
就是調用方法的意思。
如何自訂義物件?
需要透過類 Class 自訂義 Object。Class 就像一種樣板,定義出同一種類型的物件有哪些共同的屬性和方法。
例如以下的代碼定義了 Car
類別:
class Car
attr_accessor :color # 這會定義屬性 @color
def run
puts "This #{@color} car is running"
end
end
有了類,就可以用 new
來產生出物件:
car1 = Car.new
car1.color = "red"
car1.run
car2 = Car.new
car2.color = "blue"
car2.run
內建的類別
剛剛說在 Ruby 之中,每種數據類型,例如 String、Integer、Float、Array、Hash 等等,也都是物件(Object)。
這些物件,其實也都是從類別產生出來的,例如
"foobar".class
會回傳 String
是個類別
String.new("foobar")
等同於 "foobar"
[1,2,3].class
會回傳 Array
是個類別
Array.new([1,2,3])
等同於 [1,2,3]
不過因為這些數據類型太常用了,所以就不需要寫 .new
來產生,直接用符號表示就可以了。
什麽是常數 (Constant)?
在 Ruby 中,大寫開頭的變數又叫做常數,指一個數值固定不變的常量。
例如:
STATUS = ["pending", "confirmed"]
Pi = 3.1415926
所有的類別(Class)都是一種常數,所以這也是為什麽命名類別的時候一律都是大寫開頭。
10. 檔案處理
題目 28
請打開 wordcount.txt
,計算每個單字出現的次數
題目 29
請打開 todos.txt
,其中每一行就是一個待辦事項。 請編寫一個程序,可以新增和刪除代辦事項,最後可以存盤離開。 重新執行這只程序,可以繼續上次的代辦事項。
注意:gets
讀到的字串,最後都會有一個換行符號,這是一個螢幕不可見的字符,在字串中用 "\n"
表示。用 chomp
方法可以去除字串前後的空白和換行符號 "\"
。
提示說明
什麽是檔案?
所有正在執行中的程序和數據,都是放在記憶體(memory)之中。記憶體存取速度快,但是容量小而且一關機數據就不見了。 檔案則是存在硬盤上,容量大但存取慢,但是關機重來還是繼續保存著。
所謂的讀取檔案就是將數據從硬盤放進記憶體裡面,讓程序可以操作。反之寫入檔案則是將記憶體的數據寫入硬盤進行保存。
如何開檔讀取和寫入
使用 Ruby 的 File API:
讀取檔案內容:
file = File.open("foo.txt")
doc = file.read("foo.txt")
寫入檔案:
File.open("bar.txt", "w+") do |f|
f << "aaa"
f << "\n"
f << "bbb"
end
這樣就會寫入 bar.txt
,內容是 :
aaa
bbb
11. 推薦資源
如果這教程對你來說偏簡單,推薦你接下來買一本 Ruby 基礎教程, 人民郵電,如果你要找工作面試,請盡量念完這一本。
如果想繼續練習基礎編程,或是面試的公司有考算法,可以練習以下的題庫網站(請練習 Easy 程度程度即可,更高難度需要學完資料結構課程)
- Coderbyte
- LeetCode Online Judge 硅谷、BAT 大公司面試必備刷題題庫網站
- Codility 模擬線上算法測試,很刺激
如果這教程對你來說還是偏難太過抽象,建議你可以找啊哈磊的小學生坐在馬桶上都能看懂的編程入門書,會用更淺顯的對話和例子,用一整本書的長度來講這教程的內容。
其他參考資料
- 啊哈C!蹲馬桶就能看懂程式的邏輯訓練
- Exercises for Programmers
- Computer Science Programming Basics in Ruby
- Swift 程式設計入門