路遙知碼力,日久練成精- 傳說「切片」與「列表生成式」是python語法世界中好用的屠龍寶刀,當真效果這麼好用嗎?讓我們繼續看下去。
首先公佈昨天課後練習的解答:
def isLeapYear(n):
return n%4==0 and n%100!=0 or n%400==0
不知各位讀者們有想出來嗎?
接下來終於要進入我認為python精簡語法最重要的兩課了-
「切片」(slice)與「列表生成式」(List Comprehensions)。
基本上,很多python精簡的語法,
能夠使多行程式碼變一行的絕招都是靠「切片」與「列表生成式」來實現的。
「切片」與「列表生成式」就像是Python世界中的「屠龍寶刀」,
今天先將第一把刀傳授給你們吧。
假設我們有一個列表,表示早餐店的菜單,如下:
foodArr=["香雞堡", "豬肉堡", "牛肉堡", "總匯三明治", "鮪魚三明治", "火腿三明治"]
那假設我們想要取得前三個元素,可以怎麼做呢?
最普通的方法便是直接取值:
foods= [foodArr[0], foodArr[1], foodArr[2]] # ["香雞堡", "豬肉堡", "牛肉堡"]
可是假如陣列很大,
我們想要取的是前一百個元素,
這樣寫就不切實際了。
第二招是使用for迴圈,如下:
foods=[]
for i in range(3):
foods.append(foodArr[i])
但是用for迴圈又稍嫌繁瑣,
python的切片操作符就是用來簡化這種操作而設的。
切片操作符的基礎語法:
newArr = L[起始位置(包含) : 結束位置(不包含): 步長]
其中L可以是列表或是字串或是元組。
L[起始位置(包含) : 結束位置(不包含): 步長] 的意思為,
從L這個列表,取出範圍為L[起始位置] ~ L[結束位置-1]之間的數字,
每步長個間隔取一次,
若步長這個參數省略則預設為1。
也就是說,上述取出前三個元素的動作,
可以簡單用切片來取:
foodArr=["香雞堡", "豬肉堡", "牛肉堡", "總匯三明治", "鮪魚三明治", "火腿三明治"]
foods= foodArr[0:3]
如果第一個參數是0,可以省略:
>>> foodArr[:3]
["香雞堡", "豬肉堡", "牛肉堡"]
若第二個參數省略,表示從起始位置直接取到列表的結束,
例如:
>>> foodArr[3:]
['總匯三明治', '鮪魚三明治', '火腿三明治']
因此,舉一反三一下,
第一個參數和第二個參數同時省略,
就可以得到整個列表的複製。
>>> foodArr[:]
['香雞堡', '豬肉堡', '牛肉堡', '總匯三明治', '鮪魚三明治', '火腿三明治']
在記得在Day3中我們對冰箱貼標籤的例子嗎?
切片運算的效果是,
將舊列表中取出一部分元素出來,
創造一個新的列表。
至此我們已經填了第一個坑,
也就是為什麼在範例3-3中的這段程式
fridge = ['蛋糕', '蘋果', '香蕉']
b = fridge[:]
b.remove('蛋糕')
print("列表b的內容為:", b)
print("列表fridge的內容為:", fridge)
(結果:列表b的內容為: ['蘋果', '香蕉']
列表fridge的內容為: ['蛋糕', '蘋果', '香蕉']
)
可以得到這樣的效果:
這是在python中蠻特別的特性,
持以負數索引取值,
例如:
>>> foodArr[-1]
'火腿三明治'
foodArr[-n]可以便是取得列表的倒數第n個元素。
切片一樣也支持負數索引,例如取得倒數兩個元素:
>>> foodArr[-2:]
['鮪魚三明治', '火腿三明治']
我們試試更進階的吧,加入步長參數看看,
取得奇數項元素:
>>> foodArr[::2]
['香雞堡', '牛肉堡', '鮪魚三明治']
這邊把第一、二個參數都省略,
所以起始位置會從foodArr[0]開始,步長設為2,
所以會依序取得foodArr[2]、foodArr[4]的值,
直到列表的結束。
再舉一反三一下,
取得偶數項元素:
>>> foodArr[1::2]
['豬肉堡', '總匯三明治', '火腿三明治']
字串切片的用法也是一樣的,例如我們有一個存放數字的字串:
numStr= "123456789"
同樣的,我們試試字串切片的操作。
取得末四碼:
>>> numStr[-4:]
'6789'
取得'23456':
>>> numStr[1:6]
'23456'
亦可以倒著取字,
從第八個字取到第六個字:
>>> numStr[7:4:-1]
' 876'
關於此例為什麼這樣寫可能一時無法反應過來,
這邊解說一下,
因為第一個字實際上是numStr[0],
故第八個字為numStr[7]; 第六個字為numStr[5];
記得切片第二個參數是不包括該數的,
故「結束位置」設為4,
又因為是倒著取的,步長設為-1。
有了切片運算符後,我們可以很輕鬆的取得一段連續資料了,
我們再來看看range()函數的用法。
這邊把range函數跟切片放在同一篇文中介紹,
因為其實range的參數規則跟切片幾乎是相同的。
切片操作符的基礎語法為:
newArr = L[起始位置(包含) : 結束位置(不包含): 步長]
range()函數的基礎語法為:
range(起始位置(包含), 結束位置(不包含), 步長)
根本語法上就非常相似對不對?
並且,若步長這個參數省略則預設為1,
起始位置省略則預設為0。
例如:
range(5) 會生成 0,1,2,3,4
range(2,6) 會生成 2,3,4,5
range(4,21,3) 會生成 4,7,10,13,16,19
range本身是一個迭代器,
迭代器是什麼東西後續篇章還會再細說,
現在先想成是可以用for迴圈遍歷的東西都叫迭代器即可。
如果我們直接嘗試用print把它印出來,
例如:
print(range(5))
結果會顯示range(0, 5)
那要如何把裡面的數字印出來呢?
方法一是用常見的for迴圈遍歷:
for i in range(5):
print(i)
方法二是用list()將range()生成的數字轉換為list,例如
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(2,6))
[2, 3, 4, 5]
>>> list(range(4,21,3))
[4, 7, 10, 13, 16, 19]
最後,我們看一個例子以了解range()的應用。
有一對姐妹正值要出社會的年紀,
各自找到了一份工作,
姐姐的工作是每工作兩天可以放假一天,
妹妹的工作是每工作四天可以放假一天。
姐妹倆都是從九月一日開始第一天的工作。
老爸想要知道他的女兒什麼時候放假,
好安排家庭活動。
老爸需要一張當月女兒的工作排休表,
形式為一個長度為30的列表,如下:[ 1, 2, '姐姐放假', 4, '妹妹放假', '姐姐放假', …]
如果該日姐妹都要工作,直接印出當日的日期;
如果該日只有妹妹放假,印出'妹妹放假';
如果該日只有姐姐放假,印出'姐姐放假';
如果該日姐妹倆都放假,印出'姐妹都放假'。
有了range()函數步長的概念,
我們可以不必寫一堆if判斷式,
直接找規律即可。
首先我們先宣告一個具有1~30數字的列表:
holidays= list(range(1,31)) #此時holidays=[1,2,3,…,30]
(相信讀者們讀到這邊應該已經了解為什麼是range(1,31),
而不是range(1,30)了)
然後再根據有放假的日子,更新列表的值。
例如姐姐是每隔三天一次休假,
初始值是「第三天」放假,
程式如下:
for i in range(2,30,3):
holidays[i]="姐姐放假"
由於「第一天」,相當於是列表的index「0」,
故初始值設為「2」,步長為「3」。
此時列表原本位置的3,6,9,…,30都改為"姐姐放假"。
妹妹放假的邏輯類似,程式如下:
for i in range(4,30,5):
holidays[i]="妹妹放假"
另外,還要設定「姐妹都放假」的日子,
國小有學過最小公倍數的概念,
可知姐妹每隔15天會共同休假:
for i in range(14,30,15):
holidays[i]="姐妹都放假"
完整實作程式如下:
holidays= list(range(1,31))
for i in range(2,30,3):
holidays[i]="姐姐放假"
for i in range(4,30,5):
holidays[i]="妹妹放假"
for i in range(14,30,15):
holidays[i]="姐妹都放假"
print(holidays) #印出結果
今天給大家介紹的切片和range()函數就講到這邊了。
接下來就是大家最期待的課後練習時間啦。
阿拉拉參加一個唱歌選拔賽,
總共有n個評審(至少有3個),
每個評審在聽完阿拉拉的歌曲後,
會給出1~10分的分數。
為了更加客觀的評分,
給出最高分與最低分的評審分數會被去除,
僅留下其餘n-2個評審排序後的評分。
舉例來說,
假設n=10,
十位評審的評分為:
scores = [10, 10, 3, 10, 9, 10, 2, 10, 6, 5]
那麼10
分與2
分各自為最高分與最低分的分數,
因此去除這兩個分數後,
希望返回
[3, 5, 6, 9, 10, 10, 10, 10]
請實作函數judge(scores),
def judge(scores):
return #這邊輸入你要回傳的值
參數scores是一個長度至少為3的數字列表,
表示n個評審的評分,
請回傳去除最高分與最低分的評審分數後的新列表。
(提示: 別被題目所敘述的去除誤導而想到列表的remove()
函數了,
想想切片加上某個內建函數來解)
return sorted(scores)[1:-1]
好文章一定要關注的呀