跳轉到內容

Python 程式設計/列表

來自華夏公益教科書


Python 中的列表是有序的一組專案(或元素)。它是一個非常通用的結構,列表元素不必是相同型別:你可以在同一個列表中放置數字、字母、字串和巢狀列表。

Python 中的列表概覽

list1 = []                      # A new empty list
list2 = [1, 2, 3, "cat"]        # A new non-empty list with mixed item types
list1.append("cat")             # Add a single member, at the end of the list
list1.extend(["dog", "mouse"])  # Add several members
list1.insert(0, "fly")          # Insert at the beginning
list1[0:0] = ["cow", "doe"]     # Add members at the beginning
doe = list1.pop(1)              # Remove item at index
if "cat" in list1:              # Membership test
  list1.remove("cat")           # Remove AKA delete
#list1.remove("elephant") - throws an error
for item in list1:              # Iteration AKA for each item
  print(item)
print("Item count:", len(list1))# Length AKA size AKA item count
list3 = [6, 7, 8, 9]
for i in range(0, len(list3)):  # Read-write iteration AKA for each item
  list3[i] += 1                 # Item access AKA element access by index
last = list3[-1]                # Last item
nextToLast = list3[-2]          # Next-to-last item
isempty = len(list3) == 0       # Test for emptiness
set1 = set(["cat", "dog"])      # Initialize set from a list
list4 = list(set1)              # Get a list from a set
list5 = list4[:]                # A shallow list copy
list4equal5 = list4==list5      # True: same by value
list4refEqual5 = list4 is list5 # False: not same by reference
list6 = list4[:]
del list6[:]                    # Clear AKA empty AKA erase
list7 = [1, 2] + [2, 3, 4]      # Concatenation
print(list1, list2, list3, list4, list5, list6, list7)
print(list4equal5, list4refEqual5)
print(list3[1:3], list3[1:], list3[:2]) # Slices
print(max(list3 ), min(list3 ), sum(list3)) # Aggregates

print([x for x in range(10)])   # List comprehension
print([x for x in range(10) if x % 2 == 1])
print([x for x in range(10) if x % 2 == 1 if x < 5])
print([x + 1 for x in range(10) if x % 2 == 1])
print([x + y for x in '123' for y in 'abc'])

列表建立

[編輯 | 編輯原始碼]

在 Python 中建立列表有兩種不同的方法。第一種是透過賦值(“靜態”),第二種是使用列表推導式(“動態”)。

普通建立

[編輯 | 編輯原始碼]

要建立一個靜態的專案列表,請將它們寫在方括號之間。例如

[ 1,2,3,"This is a list",'c',Donkey("kong") ]

觀察

  1. 列表包含不同資料型別的專案:整數、字串和 Donkey 類。
  2. 物件可以在“執行時”建立並新增到列表中。最後一項是 Donkey 類的新例項。

建立一個新列表,其成員由非文字表達式構建

a = 2
b = 3
myList = [a+b, b+a, len(["a","b"])]

列表推導式

[編輯 | 編輯原始碼]

使用列表推導式,你可以描述建立列表的過程。為此,列表被分成兩部分。第一部分是每個元素的樣子,第二部分是你如何得到它的過程。

例如,假設我們有一個單詞列表

listOfWords = ["this","is","a","list","of","words"]

要獲取每個單詞的首字母並使用列表推導式建立列表,我們可以這樣做

>>> listOfWords = ["this","is","a","list","of","words"]
>>> items = [ word[0] for word in listOfWords ]
>>> print(items)
['t', 'i', 'a', 'l', 'o', 'w']

列表推導式支援多個 for 語句。它將按順序評估所有物件中的專案,如果一個物件比其他物件更長,則會迴圈遍歷較短的物件。

>>> item = [x+y for x in 'cat' for y in 'pot']
>>> print(item)
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']

列表推導式支援 if 語句,以便僅將滿足特定條件的成員包含到列表中

>>> print([x+y for x in 'cat' for y in 'pot'])
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'to', 'tt']
>>> print([x+y for x in 'cat' for y in 'pot' if x != 't' and y != 'o' ])
['cp', 'ct', 'ap', 'at']
>>> print([x+y for x in 'cat' for y in 'pot' if x != 't' or y != 'o' ])
['cp', 'co', 'ct', 'ap', 'ao', 'at', 'tp', 'tt']

在 2.x 版本中,Python 的列表推導式不會定義作用域。在評估完成後,任何在評估中繫結的變數都保持繫結到它們最後繫結的值。在 3.x 版本中,Python 的列表推導式使用區域性變數

>>> print(x, y)                        #Input to python version 2
t t                                    #Output using python 2

>>> print(x, y)                        #Input to python version 3
NameError: name 'x' is not defined     #Python 3 returns an error because x and y were not leaked

這與將推導式擴充套件為顯式巢狀的一組或多組“for”語句和 0 或多個“if”語句完全相同。

列表建立快捷方式

[編輯 | 編輯原始碼]

你可以將一個列表初始化為一個大小,每個元素都有一個初始值

>>> zeros=[0]*5
>>> print zeros
[0, 0, 0, 0, 0]

這對任何資料型別都有效

>>> foos=['foo']*3
>>> print(foos)
['foo', 'foo', 'foo']

但有一個需要注意的地方。當透過乘法構建一個新列表時,Python 透過引用複製每個專案。這對可變專案來說是一個問題,例如在多維陣列中,每個元素本身都是一個列表。你會認為生成二維陣列的簡單方法是

listoflists=[ [0]*4 ] *5

這有效,但可能不會按照你的預期執行

>>> listoflists=[ [0]*4 ] *5
>>> print(listoflists)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> listoflists[0][2]=1
>>> print(listoflists)
[[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]]

這裡發生的事情是 Python 使用相同的內部列表引用作為外部列表的元素。檢視這個問題的另一個方法是檢查 Python 如何看待上述定義

>>> innerlist=[0]*4
>>> listoflists=[innerlist]*5
>>> print(listoflists)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> innerlist[2]=1
>>> print(listoflists)
[[0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1, 0]]

假設上述效果不是你想要的,解決這個問題的一種方法是使用列表推導式

>>> listoflists=[[0]*4 for i in range(5)]
>>> print(listoflists)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> listoflists[0][2]=1
>>> print(listoflists)
[[0, 0, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

列表大小

[編輯 | 編輯原始碼]

要查詢列表的長度,請使用內建的 len() 方法。

>>> len([1,2,3])
3
>>> a = [1,2,3,4]
>>> len( a )
4

組合列表

[編輯 | 編輯原始碼]

列表可以通過幾種方式組合。最簡單的方法就是將它們“加”在一起。例如

>>> [1,2] + [3,4]
[1, 2, 3, 4]

另一種組合列表的方法是使用extend。如果你需要在 lambda 中組合列表,extend 是最好的方法。

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4, 5, 6]

另一種將值追加到列表的方法是使用append。例如

>>> p=[1,2]
>>> p.append([3,4])
>>> p
[1, 2, [3, 4]]
>>> # or
>>> print(p)
[1, 2, [3, 4]]

但是,[3,4] 是列表的一個元素,而不是列表的一部分。append 總是將一個元素新增到列表的末尾。因此,如果目的是連線兩個列表,請始終使用extend

獲取列表的部分(切片)

[編輯 | 編輯原始碼]

連續切片

[編輯 | 編輯原始碼]

字串類似,列表可以被索引和切片

>>> list = [2, 4, "usurp", 9.0, "n"]
>>> list[2]
'usurp'
>>> list[3:]
[9.0, 'n']

就像字串的切片是一個子字串一樣,列表的切片也是一個列表。但是,列表與字串不同的是,我們可以為列表中的專案分配新值

>>> list[1] = 17
>>> list
[2, 17, 'usurp', 9.0, 'n']

我們可以為列表的切片分配新值,它們甚至不必是相同長度

>>> list[1:4] = ["opportunistic", "elk"]
>>> list
[2, 'opportunistic', 'elk', 'n']

甚至可以透過將新值分配給空切片來將專案追加到列表的開頭

>>> list[:0] = [3.14, 2.71]
>>> list
[3.14, 2.71, 2, 'opportunistic', 'elk', 'n']

類似地,你可以透過在末尾指定空切片來將專案追加到列表的末尾

>>> list[len(list):] = ['four', 'score']
>>> list
[3.14, 2.71, 2, 'opportunistic', 'elk', 'n', 'four', 'score']

你也可以完全更改列表的內容

>>> list[:] = ['new', 'list', 'contents']
>>> list
['new', 'list', 'contents']

列表賦值語句的右側可以是任何可迭代型別

>>> list[:2] = ('element',('t',),[])
>>> list
['element', ('t',), [], 'contents']

使用切片可以建立列表的副本,因為切片返回一個新的列表

>>> original = [1, 'element', []]
>>> list_copy = original[:]
>>> list_copy
[1, 'element', []]
>>> list_copy.append('new element')
>>> list_copy
[1, 'element', [], 'new element']
>>> original
[1, 'element', []]

但是,請注意,這是一個淺複製,它包含對原始列表中元素的引用,因此請謹慎使用可變型別

>>> list_copy[2].append('something')
>>> original
[1, 'element', ['something']]

非連續切片

[編輯 | 編輯原始碼]

也可以獲取陣列的非連續部分。如果想獲取列表中每個第 n 個元素,可以使用 :: 運算子。語法是 a:b:n,其中 a 和 b 是要操作的切片的開始和結束位置。

>>> list = [i for i in range(10) ]
>>> list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list[::2]
[0, 2, 4, 6, 8]
>>> list[1:7:2]
[1, 3, 5]

比較列表

[編輯 | 編輯原始碼]

列表可以比較是否相等。

>>> [1,2] == [1,2]
True
>>> [1,2] == [3,4]
False

列表可以使用小於運算子進行比較,該運算子使用字典序

>>> [1,2] < [2,1]
True
>>> [2,2] < [2,1]
False
>>> ["a","b"] < ["b","a"]
True

排序列表

[編輯 | 編輯原始碼]

排序概覽

list1 = [2, 3, 1, 'a', 'B']
list1.sort()                                   # list1 gets modified, case sensitive
list2 = sorted(list1)                          # list1 is unmodified; since Python 2.4
list3 = sorted(list1, key=lambda x: x.lower()) # case insensitive ; will give error as not all elements of list are strings and .lower() is not applicable
list4 = sorted(list1, reverse=True)            # Reverse sorting order: descending
print(list1, list2, list3, list4)

使用 sort 方法可以輕鬆地對列表進行排序。

>>> list1 = [2, 3, 1, 'a', 'b']
>>> list1.sort()
>>> list1
[1, 2, 3, 'a', 'b']

請注意,列表是在原地排序的,sort() 方法返回None 來強調這種副作用。

如果你使用的是 Python 2.4 或更高版本,則有一些額外的排序引數

  • sort(cmp,key,reverse)
    • cmp : 用於確定任何兩個元素之間相對順序的函式
    • key : 用於獲取要對任何元素進行排序的值的函式。
    • reverse : sort(reverse=True) 或 sort(reverse=False)

Python 還包含一個 sorted() 函式。

>>> list1 = [5, 2, 3, 'q', 'p']
>>> sorted(list1)
[2, 3, 5, 'p', 'q']
>>> list1
[5, 2, 3, 'q', 'p']

請注意,與 sort() 方法不同,sorted(list) 不會在原地對列表進行排序,而是返回排序後的列表。sorted() 函式與 sort() 方法一樣也接受 reverse 引數。

連結

列表迭代

只讀迭代列表,也稱為列表的每個元素

list1 = [1, 2, 3, 4]
for item in list1:
  print(item)

可寫迭代列表

list1 = [1, 2, 3, 4]
for i in range(0, len(list1)):
  list1[i]+=1 # Modify the item at an index as you see fit
print(list)

從一個數字到另一個數字,步長為一個數字

for i in range(1, 13+1, 3): # For i=1 to 13 step 3
  print(i)
for i in range(10, 5-1, -1): # For i=10 to 5 step -1
  print(i)

滿足條件的列表中每個元素(過濾)

for item in list:
  if not condition(item):
    continue
  print(item)

另見Python程式設計/迴圈#For_Loops.

刪除也稱為刪除索引處的專案(另見#pop(i)

list1 = [1, 2, 3, 4]
list1.pop() # Remove the last item
list1.pop(0) # Remove the first item , which is the item at index 0
print(list1)

list1 = [1, 2, 3, 4]
del list1[1] # Remove the 2nd element; an alternative to list.pop(1)
print(list1)

按值刪除元素

list1 = ["a", "a", "b"]
list1.remove("a") # Removes only the 1st occurrence of "a"
print(list1)

透過複製舊列表中的過濾選擇項來建立一個新列表

list1 = [1, 2, 3, 4]
newlist = [item for item in list1 if item > 2]
print(newlist)

這使用了列表推導.

透過使用"[:]"來更新列表,保留其中過濾後的專案選擇

list1 = [1, 2, 3, 4]
sameList = list1
list1[:] = [item for item in list1 if item > 2]
print(sameList, sameList is list1)

對於更復雜的條件,可以使用單獨的函式來定義標準

list1 = [1, 2, 3, 4]
def keepingCondition(item):
  return item > 2
sameList = list1
list1[:] = [item for item in list1 if keepingCondition(item)]
print(sameList, sameList is list1)

在迭代列表時刪除專案通常會導致意外結果,除非您使用索引小心地進行操作

list1 = [1, 2, 3, 4]
index = len(list1)
while index > 0:
  index -= 1
  if not list1[index] < 2:
    list1.pop(index)

連結

有一些針對列表的算術聚合的內建函式。這些包括最小值、最大值和總和

list = [1, 2, 3, 4]
print(max(list), min(list), sum(list))
average = sum(list) / float(len(list)) # Provided the list is non-empty
# The float above ensures the division is a float one rather than integer one.
print(average)

max 和 min 函式也適用於字串列表,返回關於字母順序的最大值和最小值

list = ["aa", "ab"]
print(max(list), min(list)) # Prints "ab aa"

複製也稱為克隆列表

製作淺複製

list1= [1, 'element']
list2 = list1[:] # Copy using "[:]"
list2[0] = 2 # Only affects list2, not list1
print(list1[0]) # Displays 1

# By contrast
list1 = [1, 'element']
list2 = list1
list2[0] = 2 # Modifies the original list
print(list1[0]) # Displays 2

上述操作不會進行深複製,這有以下後果

list1 = [1, [2, 3]] # Notice the second item being a nested list
list2 = list1[:] # A shallow copy
list2[1][0] = 4 # Modifies the 2nd item of list1 as well
print(list1[1][0]) # Displays 4 rather than 2

製作深複製

import copy
list1 = [1, [2, 3]] # Notice the second item being a nested list
list2 = copy.deepcopy(list1) # A deep copy
list2[1][0] = 4 # Leaves the 2nd item of list1 unmodified
print list1[1][0] # Displays 2

另見#連續切片.

連結

清除列表

del list1[:] # Clear a list
list1 = []   # Not really clear but rather assign to a new empty list

當列表作為引數傳遞時,使用適當的方法清除列表會產生不同的結果

def workingClear(ilist):
  del ilist[:]
def brokenClear(ilist):
  ilist = [] # Lets ilist point to a new list, losing the reference to the argument list
list1=[1, 2]; workingClear(list1); print(list1)
list1=[1, 2]; brokenClear(list1); print(list1)

關鍵字:清空列表、擦除列表、清除列表、清空列表、擦除列表。

刪除重複項

[編輯 | 編輯原始碼]

從列表中刪除重複項(僅保留唯一項)可以透過以下方式實現。

如果列表中的每個專案都是可雜湊的,使用列表推導,速度很快

list1 = [1, 4, 4, 5, 3, 2, 3, 2, 1]
seen = {}
list1[:] = [seen.setdefault(e, e) for e in list1 if e not in seen]

如果列表中的每個專案都是可雜湊的,使用索引迭代,速度慢很多

list1 = [1, 4, 4, 5, 3, 2, 3, 2, 1]
seen = set()
for i in range(len(list1) - 1, -1, -1):
  if list1[i] in seen:
    list1.pop(i)
  seen.add(list1[i])

如果某些專案不可雜湊,則可以將已訪問專案集儲存在列表中

list1 = [1, 4, 4, ["a", "b"], 5, ["a", "b"], 3, 2, 3, 2, 1]
seen = []
for i in range(len(list1) - 1, -1, -1):
  if list1[i] in seen:
    list1.pop(i)
  seen.append(list1[i])

如果列表中的每個專案都是可雜湊的,並且不關心元素的順序

list1 = [1, 4, 4, 5, 3, 2, 3, 2, 1]
list1[:] = list(set(list1))  # Modify list1
list2 = list(set(list1))

在上面使用索引迭代的示例中,掃描是從末尾到開頭進行的。當這些示例被改寫為從開頭到結尾掃描時,結果似乎慢了很多。

連結

列表方法

[編輯 | 編輯原始碼]

append(x)

[編輯 | 編輯原始碼]

將專案x新增到列表末尾。

>>> list = [1, 2, 3]
>>> list.append(4)
>>> list
[1, 2, 3, 4]

pop(i)

刪除列表中索引i處的專案並將其返回。如果未提供i,則刪除列表中的最後一個專案並將其返回。

>>> list = [1, 2, 3, 4]
>>> a = list.pop(0)
>>> list
[2, 3, 4]
>>> a
1
>>> b = list.pop()
>>>list
[2, 3]
>>> b
4

運算子

[編輯 | 編輯原始碼]

連線兩個列表。

透過將給定列表連線給定次數來建立一個新列表。即 list1 * 0 == [];list1 * 3 == list1 + list1 + list1;

運算子'in' 用於兩種目的;要麼在 for 迴圈中迭代列表中的每個專案,要麼檢查列表中是否存在一個值,返回真或假。

>>> list = [1, 2, 3, 4]
>>> if 3 in list:
>>>    ....
>>> l = [0, 1, 2, 3, 4]
>>> 3 in l
True
>>> 18 in l
False
>>>for x in l:
>>>    print(x)
0
1
2
3
4

要獲取兩個列表之間的差異,只需迭代

a = [0, 1, 2, 3, 4, 4]
b = [1, 2, 3, 4, 4, 5]
print([item for item in a if item not in b])
# [0]

要獲取兩個列表之間的交集(透過保留其元素順序及其倍數),請應用與差異的差異

a = [0, 1, 2, 3, 4, 4]
b = [1, 2, 3, 4, 4, 5]
dif = [item for item in a if item not in b]
print([item for item in a if item not in dif])
# [1, 2, 3, 4, 4]

# Note that using the above on:
a = [1, 1]; b = [1]
# will result in [1, 1]

# Similarly
a = [1]; b = [1, 1]
# will result in [1]
  1. 使用列表推導構造列表 ['ab', 'ac', 'ad', 'bb', 'bc', 'bd']。
  2. 對上述列表使用切片構造列表 ['ab', 'ad', 'bc']。
  3. 使用列表推導構造列表 ['1a', '2a', '3a', '4a']。
  4. 同時從上述列表中刪除元素 '2a' 並將其打印出來。
  5. 複製上述列表並將 '2a' 添加回列表中,這樣原始列表中仍然缺少它。
  6. 使用列表推導構造列表 ['abe', 'abf', 'ace', 'acf', 'ade', 'adf', 'bbe', 'bbf', 'bce', 'bcf', 'bde', 'bdf']


解決方案

[編輯 | 編輯原始碼]

問題 1 

List1 = [a + b for a in 'ab' for b in 'bcd']
print(List1)
>>> ['ab', 'ac', 'ad', 'bb', 'bc', 'bd']

問題 2 

List2 = List1[::2]
print(List2)
>>> ['ab', 'ad', 'bc']

問題 3 

List3 = [a + b for a in '1234' for b in 'a']
print(List3)
>>> ['1a', '2a', '3a', '4a']

問題 4 

print(List3.pop(List3.index('3a')))
print(List3)
>>> 3a
>>> ['1a', '2a', '4a']

問題 5 

List4 = List3[:]
List4.insert(2, '3a')
print(List4)
>>> ['1a', '2a', '3a', '4a']

問題 6 

List5 = [a + b + c for a in 'ab' for b in 'bcd' for c in 'ef']
print(List5)
>>> ['abe', 'abf', 'ace', 'acf', 'ade', 'adf', 'bbe', 'bbf', 'bce', 'bcf', 'bde', 'bdf']
[編輯 | 編輯原始碼]
華夏公益教科書