切片和 range 的記法
range() 和切片其實很像。
range(start, stop, step)
a[start:stop:step]
都可以先記成:
start # 從哪裡開始,包含
stop # 到哪裡停止,不包含
step # 每次走幾格,也決定方向
其中最重要的是:
方向只看
step,不要看start、stop有沒有負號。
1. 先分清楚兩種負號
切片裡面的負號有兩種完全不同的意思。
負索引:代表位置
a[-3]
意思是倒數第 3 個元素。
假設:
a = [0, 1, 2, 3, 4, 5, 6]
可以這樣看:
元素 0 1 2 3 4 5 6
正索引 0 1 2 3 4 5 6
負索引 -7 -6 -5 -4 -3 -2 -1
所以:
-1 → 6
-2 → 5
-3 → 4
-4 → 3
-5 → 2
-6 → 1
-7 → 0
負索引只是表示「從尾巴數的位置」,不代表往左走。
負的 step:才代表反方向
例如:
a[5:1:-1]
第三個參數:
step = -1
所以方向是:
←
會依序使用:
5, 4, 3, 2
因此:
a[5:1:-1]
得到:
[5, 4, 3, 2]
2. 方向只看第三個參數
可以直接這樣記:
step > 0 → 往右
step < 0 → 往左
如果沒有寫 step:
a[2:5]
其實可以想成:
a[2:5:1]
所以是:
→
即使寫成:
a[-5:-2]
裡面有兩個負號,方向還是:
→
因為第三個參數沒有寫:
step = 1
所以:
start、stop 的負號只管位置。
step 的正負才管方向。
3. 三步驟記法
以後看到:
a[start:stop:step]
如果覺得很亂,就固定做三件事:
① 先看 step,決定方向
② start、stop 如果是負索引,就先轉成正索引
③ 把它當成 range(start, stop, step) 去跑
第一步:看 step
step > 0 → →
step < 0 → ←
如果沒有寫:
step = 1
第二步:負索引轉成正索引
公式:
正索引 = len(a) + 負索引
例如:
a = [0, 1, 2, 3, 4, 5, 6]
所以:
len(a) = 7
如果看到:
-4
就想:
7 + (-4)
= 3
所以:
-4 → 3
第三步:當成 range
例如:
a[2:6:2]
可以想成:
range(2, 6, 2)
會產生:
2, 4
所以拿:
a[2]
a[4]
4. 範例:a[:-4]
假設:
a = [0, 1, 2, 3, 4, 5, 6]
看到:
a[:-4]
① 看方向
沒有第三個參數,所以:
step = 1
方向 →
② 負索引轉正
len(a) = 7
-4 → 7 - 4
→ 3
所以腦中可以把:
a[:-4]
轉成:
a[:3]
③ 當成 range
因為是從最前面開始,所以想成:
range(0, 3, 1)
得到:
0, 1, 2
所以:
a[:-4]
結果:
[0, 1, 2]
5. 範例:a[-5:-6]
還是:
a = [0, 1, 2, 3, 4, 5, 6]
看到:
a[-5:-6]
不要因為看到:
-5 → -6
就覺得它會往左走。
① 看方向
沒有第三個參數:
step = 1
方向 →
② 負索引轉正
-5 → 2
-6 → 1
所以:
a[-5:-6]
可以想成:
a[2:1]
③ 當成 range
range(2, 1, 1)
但是現在:
從 2 開始
方向 →
終點卻是 1
方向不對,所以什麼都拿不到。
結果:
[]
可以直接記:
range(2, 1, 1)
→ []
a[2:1:1]
→ []
6. 如果真的要從 -5 走到 -6
要自己把方向改成往左:
a[-5:-6:-1]
① 看方向
step = -1
方向 ←
② 負索引轉正
-5 → 2
-6 → 1
所以變成:
a[2:1:-1]
③ 當成 range
range(2, 1, -1)
得到:
2
所以:
a[-5:-6:-1]
結果:
[2]
7. 再看一個比較複雜的
a[-2:-6:-1]
假設:
a = [0, 1, 2, 3, 4, 5, 6]
① 看方向
step = -1
方向 ←
② 負索引轉正
-2 → 5
-6 → 1
所以:
a[-2:-6:-1]
可以想成:
a[5:1:-1]
③ 當成 range
range(5, 1, -1)
得到:
5, 4, 3, 2
所以:
a[-2:-6:-1]
得到:
[5, 4, 3, 2]
8. slice 和 range 很像
例如:
range(2, 6, 1)
產生:
2, 3, 4, 5
而:
a[2:6:1]
使用的 index 也是:
2, 3, 4, 5
兩個都遵守:
start 包含
stop 不包含
step 決定方向與間隔
所以算切片時,把它想成 range() 很方便。
9. 但是 range 裡面的負數不能這樣轉
這一點要特別注意。
切片:
a[-4:]
這裡的:
-4
是 index(索引)。
所以可以利用:
len(a) + (-4)
轉成正索引。
但是:
range(-4, 3)
這裡的 -4 只是普通的數字 -4。
所以:
list(range(-4, 3))
結果是:
[-4, -3, -2, -1, 0, 1, 2]
不會因為某個 list 的長度而轉成正數。
所以要分清楚:
切片中的負 start / stop
→ 負索引
→ 可以利用 len(a) 轉成正索引
range() 裡面的負數
→ 普通的負數
→ 不要轉
10. [::-1] 是一個要特別注意的情況
例如:
a[::-1]
第三個參數:
step = -1
所以先知道:
方向 ←
因為 start 和 stop 都沒有寫,而且現在是反向走,所以 Python 會從最右邊開始,一直走過最左邊。
例如:
a = [0, 1, 2, 3, 4, 5, 6]
a[::-1]
得到:
[6, 5, 4, 3, 2, 1, 0]
可以先直接記成:
[::-1] → 整個反轉
要注意:
a[::-1]
不能直接寫成:
a[-1:-1:-1]
因為切片中「沒有寫 stop」和「stop 寫成 -1」不是同一件事。
目前先把:
[::-1]
當成常用特殊寫法記住即可。
11. 最簡單心法
看到:
a[x:y:z]
就固定想:
① 看 z 決定方向
z > 0 → →
z < 0 → ←
② x、y 如果是負索引
正索引 = len(a) + 負索引
③ 當成 range(x, y, z)
start 要
stop 不要
也就是:
先看第三格定方向
前兩格只管位置
負位置用 len() 轉正
最後照 range() 跑
最重要的是:
負索引不代表反向。
只有負的 step 才代表反向。