程式碼要能讓電腦讀懂,一定會有一個轉譯過程。
編譯
(Compiled language):將所有程式碼通過編譯器(compiler),編譯成電腦看得懂的機器碼,也就是0與1後,再一起執行。
.exe
檔,mac的可執行檔。C
,C++
等。直譯
(Interpreted language)或稱解譯:程式碼執行時,一行一行的由解譯器(interpreter)轉換成機器碼,並且執行。
Ruby
,Python
,Javascript
。強弱型別語言最易之區分為,程式是否對資料型態自動轉換的程度,較高者為弱型別,較弱者為強型別。
例如:
//JavaScript
Welcome to Node.js v14.15.5.
Type ".help" for more information.
> 123 + "456"
'123456'
//型別自動轉換
反之:
#Ruby
2.7.3 :001 > 123 + "456"
TypeError (String can't be coerced into Integer)
#型別無法轉換
#需更改如下
2.7.3 :002 > 123.to_s + "456"
=> "123456"
2.7.3 :003 > 123 + "456".to_i
=> 579
弱型別:型別處理感覺上較寬鬆,較容許資料隱性型別直接轉換。優點在於執行較快,但若未注意型別,可能會得到錯誤的資料。
強型別:型別處理感覺上較嚴謹,較不容許資料隱性型別直接轉換。優點在於資料型別區分清楚,但執行上較慢。
但不是絕對強型或絕對弱型,是比較級的。
動態型別語言
如之前程式碼示範,於執行階段,會藉由to_i
這類程式碼,由解譯器協助轉換型別(於執行期檢查型別),相對轉換資料類別的方法(函式,功能)較多。
wiki
動態程式語言是高階程式語言的一個類別,在電腦科學領域已被廣泛應用。它是一類在執行時可以改變其結構的語言:例如新的函式、物件、甚至代碼可以被引進,已有的函式可以被刪除或是其他結構上的變化。動態語言目前非常具有活力。眾所周知的ECMAScript(JavaScript)便是一個動態語言,除此之外如PHP、Ruby、Python等也都屬於動態語言,而C、C++、Java等語言則不屬於動態語言。
靜態型別語言
則是在編譯階段檢查型別。
並不是動態語言就一定是強型別,也不是靜態語言就一定弱型別,wiki引言內的PHP即為動態弱型別語言,Ruby則是強型別動態型語言。依照這些特性,與昨日介紹的鴨子型別介紹,前日的Ruby設計風格,可以知道Ruby的優點是較自由、口語化、類別分類清楚、且有較多語法可針對資料類型直接做轉換處理。
雖然不是刷題刷得多,一定找得到工作,但是知道的越多,要用時才不用找半天,今天繼續分享能感覺到語法懂得多是好處的題型。
Leetcode258.Add Digits
題目連結:https://leetcode.com/problems/add-digits/
題目重點:需要重複處理資料至單個數字為止。
我自己會習慣整理到自己的開發工具內,例如:
# @param {Integer} num
# @return {Integer}
def add_digits(num)
end
puts add_digits(38) #=> 2
puts add_digits(0) #=> 0
但建議能習慣於直接在Leetcode上直接操作較好。
題目需要每個數字相加。
2.7.3 :005 > 3 + 8
=> 11
#大於10,要繼續處理。
2.7.3 :006 > 1 + 1
=> 2
#將Integer拆成每個數字分開的狀態
2.7.3 :032 > 38.to_s.split""
=> ["3", "8"] #喔,還要變成數字...
2.7.3 :034 > ["3", "8"].map {|str|str.to_i}
=> [3, 8]
#再將數字相加後判斷是否大於2位數(所以是大於9)
2.7.3 :035 > [3, 8].sum
=> 11
#如果是重複處理,就再如第一條重複處理。
2.7.3 :037 > 11.to_s.split""
=> ["1", "1"]
2.7.3 :038 > ["1", "1"].map {|str|str.to_i}
=> [1, 1]
2.7.3 :039 > [1, 1].sum
=> 2
整理後如下。
def add_digits(num)
num = num.to_s.split""
num = num.map {|str| str.to_i}.sum
num > 9 ? add_digits(num) : num
end
但是如果認識digits
這個語法
def add_digits(num)
num = num.digits.sum
num > 9 ? add_digits(num) : num
end
2.7.3 :056 > 38.digits
=> [8, 3]
補充
#利用正整數的除9的餘數 == 正整數每個數相加到最後這個原理
def add_digits(num)
num == 0 ? 0 : (num%9 == 0 ? 9 : num%9)
end
def
if num == 0
0
elsif num%9 == 0
9
else
num%9
end
個人還是喜歡用digits
,Integer.digits => 數字的數字們,真的很口語化。
再一題顯示多了解語法的好處。
Leetcode283.Move Zeroes
題目連結:https://leetcode.com/problems/move-zeroes/
題目重點:要求不做一個新Array。
def move_zeroes(nums)
end
puts move_zeroes([0,1,0,3,12]) #=> [1,3,12,0,0]
puts move_zeroes([0]) #=> 0
這題是可以用快慢指針解法,我先換一個小一點的例子。
* #檢查用的指針
[0, 1, 0, 1]
$ #標記用的指針
先檢查第一個數值是0,那我先不動它,標記它是0。
* #檢查指針
[0, 1, 0, 1]
$ #零在這裡喔
檢查第二個。
* #檢查指針到第二個位置了
[0, 1, 0 ,1]
$
發現不是零,那要交換。
* #檢查指針
[1, 0, 0 ,1]
$ #Array中,位置+1 就交換了,所以檢查指針是零時標記指針不動,不是零時+1。
繼續往前檢查。
* #檢查指針
[1, 0, 0 ,1]
$ #零在這裡喔
是零,那檢查指針往前。
* #檢查指針
[1, 0, 0 ,1]
$ #零在這裡喔
不是零,跟標記的零交換吧。
*
[1, 1, 0, 0]
$ #標記位置+1
檢查指針跑完了,也排完了。
#原諒我打字累了,我直接整理吧
def move_zeroes(nums)
pointer_fast = 0
pointer_slow = 0
for pointer_fast in 0..(nums.size-1) do
if nums[pointer_fast] != 0
nums[pointer_fast], nums[pointer_slow] = nums[pointer_slow], nums[pointer_fast]
pointer_slow += 1
end
end
nums
end
換成map.with_index,也感覺沒簡單很多。
def move_zeroes(nums)
slow = 0
nums.map.with_index do |num, index|
if num != 0
nums[index], nums[slow], = nums[slow], nums[index]
slow += 1
end
end
end
試試口語化的Ruby語法吧
def move_zeroes(nums)
# 我要知道我有幾個零
# 把數列中的零都去掉後
# 從陣列後面加回去
end
def move_zeroes(nums)
zero_count = nums.count(0)
nums.delete(0)
zero_count.times {nums.push(0)}
end
#簡單易懂許多
這還不夠簡單,就試試大神分享的咒語吧!
def move_zeroes(nums)
#陣列呀,依照0是比較大的往後排吧!
end
def move_zeroes(nums)
nums.sort_by! { |num| num.zero? ? 1 : 0 }
end
我又開始不正經了
沒有錯,在一開始,除非剛好看過,怎麼可能知道利用sort_by
。
沒有練習,只有看,可能看完一個class內所有方法時,前一個class的方法就都忘光了。
所以只有練習再練習,沒看過的神奇語法,就去瞭解怎麼用。
多用幾次,就會是自己的了。
首先sort_by
與sort_by!
的差異
2.7.3 :058 > str = ["abc", "ab", "a"]
=> ["abc", "ab", "a"]
2.7.3 :059 > str.sort_by {|s|s.length}
=> ["a", "ab", "abc"]
2.7.3 :060 > str
=> ["abc", "ab", "a"]
#可以發現,雖然有回傳["a", "ab", "abc"],但str本身並無改變。
2.7.3 :061 > str.sort_by! {|s|s.length}
=> ["a", "ab", "abc"]
2.7.3 :062 > str
=> ["a", "ab", "abc"]
#多了!後str自身改變了。
再來將程式碼改回用do...end
,以及不用三元運算子
[0,1,0,3,12].sort_by! do |num|
if num == 0
1
else
0
end
end
=> [1, 3, 12, 0, 0]
#依照如果0給1這個比較大的值,不是0的給與0這個比較小的值,依照給予的值來排列。
#即使是寫
2.7.3 :071 > [0,1,0,3,12].sort_by! {|nun|nun.zero? ? 999:9}
=> [1, 3, 12, 0, 0]
#也是一樣的意思,只是這樣寫會被唸....
如果還是看不懂,沒關係,那我們再多看看程式碼。
2.7.3 :081 > [5, 2, 7, 8, 3, 1].sort
=> [1, 2, 3, 5, 7, 8]
#sort語法本身就是依照值的大小排
2.7.3 :082 > [5, 2, 7, 8, 3, 1].sort_by {|num| num}
=> [1, 2, 3, 5, 7, 8]
#sort_by,很直覺感覺就是可以依照我們指定的規則來排序,沒有就是依照原本小到大的規則。
nums.sort_by! { |num| num.zero? ? 1 : 0 }
# if == 0 那就給你比較大的值 1,if != 0 那就給你比較小的值 0。
#即使改寫如下,一樣的意思,規則定好枚舉方法,block內就會是你的許願池
2.7.3 :084 > [0,1,0,3,12].sort_by! {|nun| nun != 0 ? 0 : 1}
=> [1, 3, 12, 0, 0]
1.Ruby是直譯,動態類型,強型別語言。2.Ruby真好玩,快來學!
明日開始對Ruby更好玩的部分block
做說明,一樣會盡量以實作取代說明。