2017-04-26

Java 腦袋學 Python List

各種程式語言除了像是 int、float、boolean 與 string 等基本型別以外,最常見也必備的型別就是 list 與 map 了。

在 Java 分別是 java.util.List 與 java.util.Map,在 Python 叫做 list 與 dict,概念都是一樣的。
  • list 有順序,map 沒有
  • list 用整數做 index,map 為 key-value pair
  • list 允許重複的值,map 的 key 為 unique
但使用或語法上卻大大的不同。
list = ['A', 'B']
print(list) # ['A', 'B']
print(type(list)) # <class 'list'>
Python 的 list 宣告是用中括號與逗號,item 可以跨型別(只要自己記得誰是誰就好)。

在 Python,list 與 str 都是 sequence,只是 str 是 sequence of char,而 list 是 sequence of any object。

用 for-in 掃過整個 list。
li = list('Python')
for v in li:
    print(v)
# P
# y
# t
# h
# o
# n
用 index 存取 list 中的 item,若 index 超出範圍,會得到 IndexError。

index 必須是 int,不可以其他任何型別,包括 float 也不行,否則會得到 TypeError。

但有趣的是可以使用負整數的 index,例如 -1 表示 list 裡最後一個 item。

list = ['A', 'B']
print(list[0]) # 'A'
print(list[-1]) # 'B'
  • [n]:指定 index 的 item
  • [-n]:指定 index 的 item,從後面開始數
list 的 item 可以是任何型別,包括 list,也就是允許巢狀 list,可以用 list[0][1] 存取巢狀 list。

Python 唯二不用管縮排的地方,list item 是其中一個,因為有時候 item 太多時,勢必要換行。
list = ['A', 'B',
        'C',
'D',
    'E',
        'F']
print(list); # ['A', 'B', 'C', 'D', 'E', 'F']
另一個是搭配續行符號 \ 的長字串。
str = 'Whether you are new to programming or an experienced developer, ' + \
'it is easy to learn and use Python. ' + \
    'Python source code and installers are available ' + \
        'for download for all versions! '
print(str);
而且用了續行符號就一定要換行,不然也會報錯。
str = 'Whether you are ' + 'new to programming ...' # OK
str = 'Whether you are ' + \
      'new to programming ...' # OK
str = 'Whether you are ' + \ 'new to programming ...' # Error - unexpected character...
str = 'Whether you are ' +
'new to programming ...' # Error - invalid syntax

好用的 slice 語法

Python 用中括號建立 list,也是用中括號存取 list 裡的 item 們,slice 語法為中括號裡用冒號區隔起訖兩個 index,slice 是回傳一個新建的 list,並沒有修改原 list。
list = [0, 1, 2, 3, 4, 5]
print(list[1:3]) # [1, 2]
print(list[1:-1]) # [1, 2, 3, 4]
print(list[2:]) # [2, 3, 4, 5]
print(list[:3]) # [0, 1, 2]
print(list[:]) # [0, 1, 2, 3, 4, 5]
  • [m:n]:index 從 m 到 n-1 的所有 item,也就是包括 m,但不包括 n
  • [m:-n]:slice 語法一樣可以使用負的 index
  • [m:]:index 從 m 到結尾的所有 item
  • [:n]:index 從 0 到 n-1 的所有 item
  • [:]:index 從 0 到結尾的所有 item,可以用來複製 list,但若是就複製來說,有專門的函式可以用(copy.copy() 與 copy.deepcopy())
完整的 slice 語法請參考無極限的 Python Slice 語法

搭配 slice 的指定語法。
li = list('Python')
print(li) # ['P', 'y', 't', 'h', 'o', 'n']
li[:4] = ['P', 'Y'] # 太變態了
print(li) # ['P', 'Y', 'o', 'n']

len()

len() 可以取得 list 中的 item 數量。

+ 運算子

list 串接。
list1 = [0, 1, 2]
list2 = [3, 4, 5]
list3 = list1 + list2;
print(list1) # [0, 1, 2]
print(list2) # [3, 4, 5]
print(list3) # [0, 1, 2, 3, 4, 5]
+ 也可以用來增加 item 到既有 list 中,只是比較費工不直覺,一般是用 list 的 insert() 與 append() 兩個 method。
list1 = [0, 1, 2]
list2 = list1 + [3]
print(list2) # [0, 1, 2, 3]
也可以搭配 += 增強型指定運算子使用。
list1 = [0, 1, 2]
list2 = [3, 4, 5]
list1 += list2
print(list1) # [0, 1, 2, 3, 4, 5]
+= 增強型指定運算子可以用在 int、float、str 與 list 上。

list.extend()

類似 + 運算子,只是修改原物件。
li1 = list('Hello ')
li2 = list('Python')
li1.extend(li2) # None
print(li1) # ['H', 'e', 'l', 'l', 'o', ' ', 'P', 'y', 't', 'h', 'o', 'n']
print(li2) # ['P', 'y', 't', 'h', 'o', 'n']

* 運算子

list 複製。
list1 = [0, 1, 2]
list2 = list1 * 3
print(list1) # [0, 1, 2]
print(list2) # [0, 1, 2, 0, 1, 2, 0, 1, 2]
也可以搭配 *= 增強型指定運算子使用。
list1 = [0, 1, 2]
list1 *= 3
print(list1) # [0, 1, 2, 0, 1, 2, 0, 1, 2]
*= 增強型指定運算子可以用在 int、float、str 與 list 上。

range()

range() 得到只是類似 list 的 sequence。
r = range(3)
print(r) # range(0, 3)
for i in r:
    print(i)
# 0
# 1
# 2
上述語法如同以下的 list。
list = [0, 1, 2]
print(list) # [0, 1, 2]
for i in list:
    print(i)
# 0
# 1
# 2
在 for 迴圈中同時取到 list 的 index 與 item 的作法,需要借助 range() 與 len()。
list = [0, 1, 2]
for i in range(len(list)):
    print(str(i) + ' > ' + str(list[i]))
# 0 > 0
# 1 > 1
# 2 > 2

in 與 not in

可以用來檢查 list 中否存在某個 item,是 item 唷,不是 index。
list = ['A', 'B', 'C']
print('A' in list) # True
print('B' not in list) # False

多重指定

這是一個方便有趣但 Java 沒有的功能。

假設一個 list 有三個 item,可以用一行語法將三個 item 以不同的變數指定取得。
list = ['A', 'B', 'C']
a, b, c = list
print(a, b, c, sep=', ') # A, B, C
不只 list,多重指定也可以用在 tuple 上。
tuple = ('A', 'B', 'C')
a, b, c = tuple
print(a, b, c, sep=', ') # A, B, C
但要小心變數的數量必須要 item 數量一樣,否則會得到 ValueError。

多重指定最神奇的用法在這,交換變數,以前交換兩個變數的內容都要透過第三個 temp 變數,現在不用了。
a = 'A'
b = 'B'
a, b = b, a
print(a, b, sep = ', ') # B, A
其實說穿了不神奇,等號右邊的 b, a 事實上是一個 tuple,tuple 正確的語法只要逗號,不需要小括號,因此上面的語法就只是 a, b = tuple 而已,因此可以延伸出 a, b, c = b, c, a 之類的。

list 的 method

大多數 list 的 method 會動原 list 並回傳 None,而 Python 內建的 function 則是回傳新的 list,不會動原 list。

list.index()

每種資料型別都有內建的 method 可以使用。

index() 回傳 item 所在的 index,如果存在重複的 item,則回傳「第一個」符合的 item index,如果 item 不存在得 ValueError。
list = ['A', 'B', 'C', 'B']
print(list.index('B')) # 1
print(list.index('D')) # ValueError

list.append()

新增 item 到 list 最後面,是修改原 list,並不是新增 list,而且回傳的是 None。
list = ['A', 'B', 'C']
print(list.append('D')) # None
print(list) # ['A', 'B', 'C', 'D']

list.insert()

新增 item 到 list 中指定的位置,其後的所有 item 往後移一位,是修改原 list,並不是新增 list,而且回傳的是 None。
list = ['A', 'B', 'C']
print(list.insert(0, 'D')) # None
print(list) # ['D', 'A', 'B', 'C']

list.remove()

有三種方法可以移除 list 裡的 item:list.remove()、list.pop() 與 del(),list.remove() 是指定 item,list.pop() 與 del() 是用 index。

移除 list 中指定的 item,其後的所有 item 往前移一位,如果存在重複的 item,只移除第一個符合的 item,是修改原 list,並不是新增 list,而且回傳的是 None,如果 item 不存在得 ValueError。

類似 del,只是 del 用 index 移除 item,而 remove() 用 item 移除。
list = ['A', 'B', 'C']
print(list.remove('B')) # None
print(list) # ['A', 'C']
print(list.remove('D')) # ValueError

list.pop()

取出並移除 list 中指定 index 的 item,其後的所有 item 往前移一位,修改原 list。

類似 del,只是 del 回傳 None,pop() 回傳被 del 的 item。
li = list('Python')
print(li) # ['P', 'y', 't', 'h', 'o', 'n']
print(li.pop(1)) # y
print(li) # ['P', 't', 'h', 'o', 'n']
print(li.pop()) # n,預設是最後一個
print(li) # ['P', 't', 'h', 'o']

del

刪除指定 index 的 item,後面的 item 往前移一位。
list = [0, 1, 2]
print(list) # [0, 1, 2]
del list[1]
print(list) # [0, 2]
也可以用 [m:n] 一次 del 一整段。

sorted() & list.sort()

對 list 裡的 item 進行排序,但僅限於 int 與 str 組成的 list,且不能混合不同型別,否則得 TypeError

sorted() 是回傳新 list,不是修改原 list,而 list.sort() 是修改原 list,回傳 None。

反向排序使用關鍵字參數 reverse = True,忽略大小寫排序使用關鍵字參數 key = str.lower,小寫在前大寫在後,但是改用 key = str.upper 一樣是小寫在前大寫在後。
list = ['c', 'B', 'a', 'A', 'b', 'C']
print(sorted(list)) # ['A', 'B', 'C', 'a', 'b', 'c']
print(list) # ['c', 'B', 'a', 'A', 'b', 'C']
print(list.sort()) # None
print(list) # ['A', 'B', 'C', 'a', 'b', 'c']
print(list.sort(reverse = True)) # None
print(list) # ['c', 'b', 'a', 'C', 'B', 'A']
print(list.sort(key = str.lower)) # None
print(list) # ['a', 'A', 'b', 'B', 'c', 'C']
print([1, 'A'].sort()) # TypeError

join() & split()

str 和 list 很常用的 split 與 join 方法,比較特別的是 split 與 join 都是掛在 str 上。
print (', '.join([ 'Apple', 'Banana', 'Chocolate'])) 
# Apple, Banana, Chocolate,是用 separate char 去做 join()
print ('Apple, Banana, Chocolate'.split(', ')) 
# ['Apple', 'Banana', 'Chocolate'],separate char 預設為空白

複製/克隆 list

由於 Python list 是 mutable 資料類型,因此是 pass by reference,要克隆 list 可以透過 slice 或者 copy.copy()。
import copy
list1 = [0, 1, 2, 3]
list2 = list1
list3 = list1[:] # slice copy
list4 = copy.copy(list1)
print(list1) # [0, 1, 2, 3]
print(list2) # [0, 1, 2, 3]
print(list3) # [0, 1, 2, 3]
print(list4) # [0, 1, 2, 3]
list1.remove(2)
print(list1) # [0, 1, 3]
print(list2) # [0, 1, 3]
print(list3) # [0, 1, 2, 3]
print(list4) # [0, 1, 2, 3]
用 slice 語法或者 copy.copy() 做的只是淺層複製,若要深層複製,也就是針對巢狀 list,只能用 copy.deepcopy()。
import copy
list1 = [0, 1, 2, ['A', 'B', 'C']]
list2 = list1
list3 = list1[:] # slice copy
list4 = copy.deepcopy(list1)
print(list1) # [0, 1, 2, ['A', 'B', 'C']]
print(list2) # [0, 1, 2, ['A', 'B', 'C']]
print(list3) # [0, 1, 2, ['A', 'B', 'C']]
print(list4) # [0, 1, 2, ['A', 'B', 'C']]
list1.remove(2) # remove 2
list1[2].remove('B') # remove 'B'
print(list1) # [0, 1, ['A', 'C']]
print(list2) # [0, 1, ['A', 'C']]
print(list3) # [0, 1, 2, ['A', 'C']]
print(list4) # [0, 1, 2, ['A', 'B', 'C']]
---
---
---

沒有留言:

張貼留言