一、引言
關(guān)鍵點:一個列表可以存儲任意大小的數(shù)據(jù)集合。
????????程序一般都需要存儲大量的數(shù)值。假設(shè),舉個例子,需要讀取100個數(shù)字,計算出它們的平均值,然后找出多少個數(shù)字是高于這個平均值的。程序首先讀取100個數(shù)字并計算它們的平均值,然后把每個數(shù)字和平均值進(jìn)行比較來確定它是否超過了平均值。為了完成這個任務(wù),這些數(shù)字都必須存儲在變量內(nèi)。為了這樣做,你必須創(chuàng)建100個變量并且重復(fù)編寫幾乎同樣的一段代碼100次。顯然,編寫一個這樣的程序是不切實際的。因此,這個問題該怎么,解決?
????????我們需要一個高效、條理的方式。Python 提供了一種被稱為列表的數(shù)據(jù)類型,它可以存儲一個有序的元素集合。
二、列表基礎(chǔ)
關(guān)鍵點:列表是一個用list類定義的序列,它包括了創(chuàng)建、操作和處理列表的方法。列表中的元素可以通過下標(biāo)來訪問。
2.1 創(chuàng)建列表
list類定義了列表。為了創(chuàng)建一個列表,可以使用list的構(gòu)造方法,如下所示:
list1 = list() # Create an empty list
list2 = list([2,3,4]) # Create a list with elements 2,3,4
list3 = list(["red", "green", "blue"]) # Create a Tist with strings
list4 = list(range(3, 6)) # Create a list with elements 3, 4,5
list5 = list("abcd") # Create a list with characters a,b,C,d
也可以使用下面這個更簡單一些的語法來創(chuàng)建列表:
listl = [] # Same as 1ist()
list2 = [2,3,4] # Same as list([2,3,4])
list3 = ["red", "green"] # Same as list(["red", "green"])
列表中的元素用逗號分隔并且由一對中括號([ ])括住。
注意:一個列表既可以包含同樣類型的元素也可以包括不同類型的元素。例如,下面的列表也是可以的:
list4 =[2, "three", 4]
2.2 列表是一種序列類型
????????Python中的字符串和列表都是序列類型。一個字符串是一個字符序列,而一個列表則是任何元素的序列。序列的常用操作被總結(jié)在表10-1 中。對字符串的序列操作同樣適用于列表。
2.3 列表使用的函數(shù)
????????一些Python內(nèi)嵌函數(shù)可以和列表一起使用。可以使用len函數(shù)返回列表的元素個數(shù),使用max/min函數(shù)返回列表中的最大值元素和最小值元素,而sum函數(shù)返回列表中所有元素之和。還可以使用random模塊中的shuffle函數(shù)隨意排列列表中的元素。下面是一些例子:
>>> list1 = [2, 3,4,1,32]
>>> len(list1)
5
>>> max(list1)
32
>>> min(list1)
1
>>> sum(list1)
42
>>> import random
>>> random.shuffle(list1) # Shuffle the elements in 1ist1
>>> list1
[4,1,2,32,3]
>>>
2.4 下標(biāo)運算符[ ]
一個列表中的元素都可以使用下面的語法通過下標(biāo)操作符訪問:
myList[index]
列表下標(biāo)是基于0的,也就是說,下標(biāo)的范圍從0到len(myList)-1,如圖10-1 中闡述:myList[index]可以像變量一樣使用,所以它也被稱為下標(biāo)變量。例如:下面的代碼將myList[0]與myList[1]中的值相加并賦給myList[2]。
myList[2] = myList[0] + myList[1]
下面的循環(huán)將0賦值給myList[0]、將1賦值給myList[1]、...、將9賦值給myList[9]:
警告:越界訪問列表是一個常見的程序設(shè)計錯誤,它會導(dǎo)致一個運行時的“IndexError” 。為了避免這種錯誤,要確保沒有使用超出len(myList)-1的下標(biāo)。
2.5 列表截取[start:end]
????????下標(biāo)運算符允許選擇一個指定下標(biāo)位置上的元素。而截取操作使用語法list[start:end] 返回列表的一個片段。這個片段是下標(biāo)從start到end-1的元素構(gòu)成的一個子列表。下面是一些例子:
>>> list1=[2,3,5,7,9,1]
>>> list1[2 : 4]
[5, 7]
>>>
起始下標(biāo)和結(jié)尾下標(biāo)是可以省略的。在這種情況下,起始下標(biāo)為0而結(jié)尾下標(biāo)是最后一個下標(biāo)。
注意:如果start>=end,那么list[start:end] 將返回一個空表。如果end指定了一個超出列表結(jié)尾的位置,那么Python 會將使用列表長度替代end。
2.6? +、*和in/not in運算符
????????可以使用連接運算符(+)來組合兩個列表,使用復(fù)制運算符(*)復(fù)制列表中的元素。下面是一些例子:
>>> list1 = [2,3]
>>> 1ist2
[1,9]
>>> list3 = 1ist1 + 1ist2
>>> 1ist3
[2, 3,1,9]
>>>
>>> list4 = 3 * list1
>>> list4
[2, 3,2,3,2,3]
>>>
????????通過連接list1 和list2就會得到一個新列表(第3行)。第7行將list1復(fù)制三次以創(chuàng)建一個新列表。注意: 3*list1和list1*3相同。
????????可以使用in或者not in運算符來判斷一個元素是否在列表中。例如:
>>> list1 = [2,3,5,2,33, 21]
>>> 2 in listl
True
>>> 2 not in list1
False
>>>
2.7 使用for循環(huán)遍歷元素
????????Python列表中的元素是可迭代的。Python支持一種便利的for循環(huán),它可以讓你在不使用下標(biāo)變量的情況下順序遍歷列表。例如,下面的代碼顯示列表mylist中的所有元素。
for u in myList:
print(u)
可以這樣讀代碼:“對于mylist中的每個元素u,輸出它?!?br> ????????如果希望以不同的順序遍歷列表或者改變列表中的元素,那么仍然必須使用下標(biāo)變量。
例如,下面的代碼顯示奇數(shù)位置上的元素。
for i in range(0, len(myList), 2):
print(myList[i])
2.8 比較列表
????????可以使用比較運算符(>、>=、<、<=、==、!=)對列表進(jìn)行比較。為了進(jìn)行比較,兩個列表必須包含同樣類型的元素。比較使用的是字典順序:首先比較前兩個元素,如果它們不同就決定了比較的結(jié)果;如果它們相同,那就繼續(xù)比較接下來兩個元素,一直重復(fù)這個過程,直到比較完所有的元素。下面是一些示例。
>>> listl = ["green", "red", "blue"]
>>> list2 = ["red", "blue", "green"]
>>> list2 == listl
False
>>> list2 != list1
True
>>> list2 >= listl
True
>>> list2 > list1
True
>>> list2 < list1
False
>>> list2 <= listl
False
>>>
2.9 列表解析
????????列表解析提供了一種創(chuàng)建順序元素列表的簡潔方式。一個列表解析由多個方括號組成,方括號內(nèi)包含后跟一個for子句的表達(dá)式,之后是0或多個for或if子句。列表解析可以產(chǎn)生一個由表達(dá)式求值結(jié)果組成的列表。這里是一些例子。
>>> list1 = [ x for x in range(5)] #Returnsalistof0,1,2,3,4
>>> list1
[0,1,2,3,4]
>>>
>>> list2 = [0.5 * x for x in list1]
>>> list2
[0.0,0.5,1.0,1.5,2.0]
>>>
>>> list3 = [x for x in list2 if x < 1.5]
>>> list3
[0.0, 0.5,1.0]
>>>
2.10 列表方法
一旦列表被創(chuàng)建,可以使用list類的方法(如圖10-2 所示)來操作列表。
2.11 將字符串分成列表
????????str類包括了split 方法,它對于將字符串中的條目分成列表是非常有用的。例如,下面的語句:
items = "Jane John Peter Susan".split()
????????就會將字符串“Jane John Peter Susan”分離成列表['Jane' ,'John', 'Peter' ,'Susan']。在這種情況下,字符串中的條目是被空格分隔的??梢允褂靡粋€非空格的限定符。例如,下面的語句:
items = "09/20/2012".split("/")
將字符串“09/20/2012” 分成了列表['09','20', '2012']。
注意: Python 支持正則表達(dá)式,它是一種使用模式來匹配和分隔字符串的最有效且最有力的特征。正則表達(dá)式對于初學(xué)者來講是復(fù)雜的。
2.12 輸入列表
????????可能經(jīng)常需要編寫代碼從控制臺將數(shù)據(jù)讀入列表??梢栽谘h(huán)里每一行輸入一個數(shù)據(jù)條目并將它追加到列表。例如:下面的代碼將10個數(shù)字讀入一個列表,每一行讀一個數(shù)字。
lst = [] # Create a list
print("Enter 10 numbers: ")
for i in range(10) :
lst.append(eval(input())
????????有時候在一行中以空格分隔數(shù)據(jù)會更加方便。可以使用字符串的split方法從一行輸入中提取數(shù)據(jù)。例如:下面的代碼從-行讀取10個空格分隔的數(shù)給列表。
# Read numbers as a string from the console,
s = input("Enter 10 numbers separated by spaces from one line: ")
items = s.split() # Extract items from the string
lst = [eval(x) for x in items] # Convert items to numbers
????????調(diào)用input()來讀取一-個字符串。使用s.split()來提取字符串s中被空格分隔的條目并返
回列表中的條目。最后一行通過將條目轉(zhuǎn)化成數(shù)字來創(chuàng)建一個數(shù)字列表 。
2.13 對列表移位
????????有時候,需要將列表中的元素向左或向右移動。Python并沒有在list類中提供這樣的方法,但是可以編寫下面的函數(shù)來實現(xiàn)向左移。
2.14 簡化代碼
????????列表可以大大簡化某些任務(wù)的。例如:假設(shè)你希望通過給定的月份數(shù)字來得到月份的英文名。如果月份名被存儲在一個列表中,那么給定月份的名字可以簡單地通過下標(biāo)訪問。下面的代碼提示用戶輸人月份數(shù),然后顯示它的月份名:
months = ["January", "February", "March", ...., "December"]
monthNumber = eval(input("Enter a month number (1 to 12): "))
print("The month is", months [monthNumber - 1])
????????如果不使用months列表,你就只能使用一個冗長的多重if-else語句來決定月份名,如下所示:
if monthNumber == 0:
print("The month is January")
elif monthNumber == 1:
print("The month is February")
else:
print("The month is December")
三、復(fù)制列表
關(guān)鍵點:為了將一個列表中的數(shù)據(jù)復(fù)制給另一個列表,必須將元素逐個地從源列表復(fù)制到目標(biāo)列表。
????????經(jīng)常需要在程序中復(fù)制一個列表或列表的一部分。在某些情況下,可能會嘗試使用賦值語句(=),如下所示:
list2 = list1
????????但是,這條語句不會將listl1引用的列表內(nèi)容復(fù)制給list2 ;事實上,它僅僅將list1引用值賦給list2。在這條語句之后,list1 和list2都將指向同一個列表,如圖10-7所示。list2 之前指向的列表將不再被引用,它就變成了垃圾( garbage)。list2 所占用的內(nèi)存空間將被自動收集起來被Python編譯器重新使用。
為了將listl完全相同地復(fù)制給list2,可以使用:
list2 = [x for x in list1]
或者簡化為:
list2 = [] + list1
四、將列表傳遞給函數(shù)
關(guān)鍵點:當(dāng)列表被傳遞給函數(shù)時,由于列表是一個可變對象,所以列表的內(nèi)容可能會在函數(shù)調(diào)用后改變。
????????因為列表是一個對象,所以將列表傳遞給函數(shù)就像給函數(shù)傳遞一個對象。例如:下面的函數(shù)顯示列表中的元素。
def printList(lst) :
for element in 1st:
print(e1 ement)
可以通過傳遞列表來調(diào)用它。例如:下面的語句調(diào)用printlist 函數(shù)顯示3、1、2、6、4和2。
printList([3,1,2,6,4,2])
注意:前面的語句創(chuàng)建了一個列表,然后把它傳遞給函數(shù)。這里沒有顯示指向列表的引用變量。這樣的列表被稱作匿名列表。
????????因為列表是可變對象,所以列表的內(nèi)容可能會在函數(shù)內(nèi)改變。
五、從函數(shù)返回一個列表
關(guān)鍵點:當(dāng)函數(shù)返回一個列表時,就會返回這個列表的引用值。
????????在調(diào)用函數(shù)時可以傳遞列表參數(shù)。函數(shù)也可以返回列表。例如:下面的函數(shù)返回了一個列表,它是另一個列表倒置的結(jié)果。
????????第2行創(chuàng)建一個新列表result。第4~5行將名為lst的列表中的元素復(fù)制給名為result的列表。第7行返回這個列表。例如:下面的語句返回元素為6、5、4、3、2和1的新列表list2。
list1=[1,2,3,4,5,6]
list2 = reverse(list1)
注意: list 類有reverse()方法,可以調(diào)用它來倒置一個列表。
六、?查找列表
關(guān)鍵點:如果一個列表是排好序的,那么要查找一個列表中的某個元素,二分查找比線性查找更高效。
????????查找是在列表中查找一個特定元素 的方法。例如:判定某個分?jǐn)?shù)是不是包含在一個分?jǐn)?shù)列表里。list 類提供了index 方法來查找并返回匹配列表中某個元素的下標(biāo)。它也支持in和not in運算符以決定一個元素是否在列表中。
6.1、線性查找法
????????線性查找法順序地將關(guān)鍵元素key和列表中的每一個元素進(jìn)行比較。它連續(xù)這樣做,直到這個關(guān)鍵字匹配列表中的某個元素,或者在沒有找到匹配元素時已經(jīng)查找完整個列表。如果找到一個匹配元素,那么線性查找將返回匹配元素在列表中的下標(biāo)。如果沒有匹配,那么查找返回-1。程序清單10-9 中的linearSearch函數(shù)可以解釋這個方法。
????????為了更好地理解這個函數(shù),使用下面的語句對程序進(jìn)行跟蹤。
lst = [1,4,4,2,5,-3,6,2]
i = linearSearch(1st, 4) # Returns 1
j = linearSearch(1st,-4) # Returns -1
k = linearSearch(1st, -3) # Returns 5
????????線性查找函數(shù)將關(guān)鍵字和列表的每一個 元素進(jìn)行比較。這些元素可以是任意順序。如果這,個元素存在,那么算法在找到這個關(guān)鍵字之前需要平均檢測列表的一半元素。因為線性查找的運行時間和列表中元素的數(shù)量成正比,所以對于大型列表而言,線性查找的效率是很低的。
6.2、 二分查找法
二分查找是對列表值進(jìn)行查找的另一種常用方法。想運用二分查找法,列表中的元素必須是事先排好序的。假設(shè)列表是升序排列的,那么二分查找法會首先將關(guān)鍵字和列表的中間元素進(jìn)行比較,這時需要考慮下面三種情況
- 如果關(guān)鍵字小于列表中間的元素,那么你只需要在列表的前半部分繼續(xù)尋找關(guān)鍵字。
- 如果關(guān)鍵字等于列表中間的元素,那么查找因為找到一個匹配而結(jié)束。
- 如果關(guān)鍵字大于列表中間的元素,那么你只需要在列表的后半部分繼續(xù)尋找關(guān)鍵字。
????????注意:毫無疑問,二分查找法每次比較之后都排除了一半的列表。有時排除一半的元素,有時排除一半加一個元素。假定這個列表有n個元素。為方便起見,假設(shè)n是2的冪。在第一次比較之后,n/2 個元素被留下來進(jìn)行下一步比較;在第二次比較之后,(n/2) /2個元素被留下。在第k次比較之后,n/2的k次方個元素被留下進(jìn)行下一步查找。當(dāng)k= log2n時,列表中只剩下一個元素,只需要進(jìn)行一次比較即可。因此,在用二分查找時,最壞情況下需要進(jìn)行l(wèi)og2n+1次比較來在排序列表中找到那個元素。對于一個有著1024 (29) 個元素的列表來說,最壞情況下二分查找只需要進(jìn)行11次比較,而線性查找則需要進(jìn)行1023次比較。
????????每一次比較之后列表中需要查找的部分就減少一半,分別用low和high來表示列表中當(dāng)前要查找的第一個下標(biāo)和最后一個下標(biāo)。初始情況下,low 是0,而high是len(lst)-1。mid表示中間元素的下標(biāo),因此mid是(low+high)/2,圖10-9 給出如何利用二分查找在列表[2,4,7,10,11,45,50,59,60,66,69,70,79]中找到關(guān)鍵字11。
????????現(xiàn)在,你知道二分查找是如何工作的。下一個任務(wù)是如何用Python實現(xiàn)它。但是不要急于一下子就完全實現(xiàn)它。應(yīng)該逐步開發(fā),一次只做一步。如圖10-10a所示,可以從查找的第一次迭代開始。它將關(guān)鍵字和列表的中間元素進(jìn)行比較,這時low下標(biāo)是0而high是len(lst)-1。如果key<lst[mid],將high下標(biāo)指向mid-1 ;如果key==lst[mid],就找到了一個匹配對象,程序?qū)⒎祷豰id;如果key>lst[mid],將low下標(biāo)指向mid+1。
????????接下來,考慮添加一個循環(huán)來實現(xiàn)函數(shù)以完成重復(fù)查找,如圖10-10b所示。當(dāng)找到這個關(guān)鍵字,或者當(dāng)low>high還沒有找到,那么這個查找結(jié)束。
????????當(dāng)沒有找到關(guān)鍵字時,low 是關(guān)鍵字應(yīng)該被插入以保證列表順序的插入點。返回插入點要比返回-1更有用。這個函數(shù)必須返回一個負(fù)值來表示這個關(guān)鍵字不在列表中。能否簡單地返回-low?不可以,因為關(guān)鍵字小于lst[0]。一個好的選擇是如果關(guān)鍵字不在列表中則讓函數(shù)返回-low-1。返回-low-1不僅表示這個值不在列表中,也表示值應(yīng)該被插入的地方。
注意:線性查找法在一個小列表或未排序隊列中查找元素時很有用,但是對大型列表而言效率很低,而二分查找法更高效,但是它們需要列表是提前排好序的。
七、排序列表
關(guān)鍵點:對列表元素進(jìn)行排序的策略有很多種。選擇排序和插入排序是兩種常用方法。
????????就像查找一樣,排序也是程序設(shè)計中的一個常見任務(wù)。類list提供了sort 方法來對一個列表進(jìn)行排序。
????????已經(jīng)有很多排序算法被開發(fā)出來。下面介紹兩種簡單、直觀的排序算法:選擇排序和插入排序。通過使用這些算法,可以學(xué)會開發(fā)和實現(xiàn)其他算法的有價值的技巧。
7.1、選擇排序
????????假設(shè)你希望對一個列表進(jìn)行升序排列。選擇排序會找到列表中的最小元素并將它和第一個元素交換。然后找到剩余元素中值最小的元素并和剩余列表的第一個元素交換,依此類推,直到只剩一個元素。圖10-11給出如何運用選擇排序?qū)α斜韀2,9,5,4,8,1,6]進(jìn)行排序。
????????第一次嘗試開發(fā)一個完整的排序程序可能是比較困難的。編寫一段代碼完成第一輪迭代,它找到列表的最小元素之后和列表的第一個元素互換,然后觀察第二輪迭代時有什么不同,接著是第三輪,依此類推。這樣觀察會讓你能編寫一個推廣到所有迭代的循環(huán)。
7.2、 插入排序
????????假如想升序排列一個列表。插入排序算法是通過重復(fù)地將一個新元素插 人到一個已排好序的子列表中,直到整個列表排好序。圖10-12給出如何利用插入排序?qū)α斜韀2,9,5,4,8,1,6]進(jìn)行排序。文章來源:http://www.zghlxwxcb.cn/news/detail-652517.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-652517.html
?八、總結(jié)
- 可以利用Python內(nèi)置的len、max、min和sum函數(shù)返回一個列表的長度、列表的最大和最小值以及列表中所有元素之和。
- 可以使用random模塊中的shuffle函數(shù)將一個列表中的元素打亂。
- 可以使用下標(biāo)運算符[]來引用列表中的一個獨立元素。
- 程序員常常會錯誤地用下標(biāo)1來引用列表中的第一個元素,但它應(yīng)該是0。這被稱為下標(biāo)出1錯誤。
- 可以使用連接操作符+來連接兩個列表,使用復(fù)制運算符*來復(fù)制元素,使用截取運算符[:]獲取一個子列表,使用in和not in運算符來檢-一個元素是否在列表中。
- 可以使用for循環(huán)來遍歷列表中的所有元素。
- 可以使用比較運算符來比較兩個列表中的元素。
- 一個列表對象是可變的??梢允褂梅椒╝ppend、extend、insert、pop和remove向一個列表添加元素和從一個列表刪除元素。
- 可以使用index方法獲取列表中一個元素的下標(biāo),使用count方法來返回列表中元素的個數(shù)。
- 可以使用sort和reverse方法來對一個列表中的元素進(jìn)行排序和翻轉(zhuǎn)。
- 可以使用split方法來將一個字符串分離成列表。
- 當(dāng)調(diào)用一個帶列表參數(shù)的函數(shù)時,列表的引用則被傳遞給這個函數(shù)。
- 如果一個列表已經(jīng)排好序,那么在列表中查找一個元素時二分查找比線性查找效率更高。
- 選擇排序?qū)⒘斜碇械淖钚≡睾偷谝粋€元素交換。然后找到剩余元素中最小的元素并與剩余元素的第一個交換,依此類推,直到只剩一個元素為止。
- 插入排序算法重復(fù)地將一個新元素插入排好序的子列表中,直到整個表都排好序為止。
到了這里,關(guān)于Python程序設(shè)計——列表的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!