串列list型態

要處理一大串的資料時,串列list是最佳的選擇。

list,我們在這裡把它翻譯作「串列」,也有些人把它翻譯成「列表」或「清單」。

串列(list)是Python語言中非常重要的資料結構,也就是用來表示資料的方法。一般來說,如果我們有一個數字,都是直接表示它即可,例如下面這個例子是用一個叫做chi的變數來表示某一個同學的國文科成績:

chi = 89

但是問題來了,假設我們需要在程式裡面處理全班20位同學的國文成績,那該如何儲存在變數中呢?用以下這種方法好嗎?

chi1 = 89
chi2 = 92
chi3 = 78
...
chi20 = 98

乍看起來是可行的,但是請問一下,如果要把計算全班同學的國文平均成績,該如何計算呢?如果以上面這個方式來放在變數中的話,那麼只能用以下這種方法:

sum = chi1 + chi2 + chi3 + chi4 + chi5 + ... + chi20
average = sum / 20

這顯然不是一個明智的方法。此時,串列就是一個好的解決方式,全班的國文成績可以使用如下所示的方式來儲存(在此以10人的成績為例):

串列的操作

串列的宣告方法如下:

>>> a = list()
>>> b = []
>>> c = list('Hello')
>>> print(c)
c = ['H', 'e', 'l', 'l', 'o']

2個以上的串列物件也可以把它們串接起來,相乘以及檢查某些元素是否存在於串列中,操作的程式如下:

a = list("Hello")
b = list("World")
print("a={}".format(a))
print("b={}".format(b))
print("a+b={}".format(a + b))
print("a*4={}".format(a*4))
print("Is 'h' in a? {}".format('h' in a))
print("Is 'H' in a? {}".format('H' in a))

輸出的結果如下:

a=['H', 'e', 'l', 'l', 'o']
b=['W', 'o', 'r', 'l', 'd']
a+b=['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']
a*4=['H', 'e', 'l', 'l', 'o', 'H', 'e', 'l', 'l', 'o', 'H', 'e', 'l', 'l', 'o', 'H', 'e', 'l', 'l', 'o']
Is 'h' in a? False
Is 'H' in a? True

在上面的例子中,我們使用 in 運算子來檢視某一個資料項是否在串列中,這是非常好用的做法,因為如果不在串列中的話,檢查後就可以避免出現程式錯誤的情形。

在執行的過程中只要程式一出現錯誤,就會立即回報錯誤訊息,而且馬上中斷程式的執行,在實用的程式上要避免此種情形發生。避免的方式除了在程式設計時要仔細考慮每一種情況之外,也可以善加利用例外處理except指令,這種方式我們會在後面再加上介紹。

取出串列的方式

在串列中的每一個資料項目都有其索引編號,這些編號是從0開始,因此如果有一個具有n個資料項的串列,則它的索引值範圍是0~n-1,要存取每一個資料項只要利用中括號再加上索引值就可以了。

a = list("This is a book.")
print(a)
print(a[0], a[5])

以下是執行的結果:

['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'b', 'o', 'o', 'k', '.']
T i

其中一個'T'就是串列的第0個索引值所在的資料項,而'i'當然就是第5個索引值。那麼,如果要拿最後一個呢?len函數可以用來計算資料項的個數,所以使用以下的方式可以拿到最後一個項目:

a = list("This is a book.")
n = len(a)
print(a[n-1])

不過,在Python中沒有人會用這麼笨的方法,直接用a[-1]就可以了,如下:

a = list("This is a book.")
print(a[-1])

有了自訂索引值的概念,那麼要拿其中一個片段的字串就容易了,可以使用「:」來設定開始和結束要拿取的子字串,請參考以下的例子:

a = "This is a book."
b = list(a)
print(a)
print(b)
print(a[0:4])
print(b[0:4])
print(a[-5:])
print(b[-5:])

以下是執行的結果,是不是和你想的一樣呢?

This is a book.
['T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 'b', 'o', 'o', 'k', '.']
This
['T', 'h', 'i', 's']
book.
['b', 'o', 'o', 'k', '.']

典型的串列宣告方式

chinese_scores = [89, 92, 78, 63, 90, 89, 56, 56, 89, 59]

其實串列不一定要有名字,例如我們之前在for迴圈中使用range臨時產生的就是沒有名字的串列,同樣的概念,也可以如以下程式的方式,臨時建立一個:

for x in [1, 6, 8, 10]:

使用中括號把所有的數字放進去,則這些數字就會被當做是同一串的資料,並賦予其索引值,在第一個的是第0號,第2個的是第1號,依此類推。如上例,chinese_socres[0]的內容就是89,而chinese_scores[1]的內容就是92。

把串列型態運用在成績處理上

如上面這個資料要計算總分和平均的話,其程式如下:

chinese_scores = [89, 92, 78, 63, 90, 89, 56, 56, 89, 59]
sum = 0
for score in chinese_scores:
sum += score
print("總分:{}分,平均:{:.2f}分".format(sum, sum/10))

執行結果如下:

緦分:761分,平均:76.10分

一般來說,成績是由使用者輸入的,其程式應該如下:

成績計算程式

chinese_scores = list()
score = int(input("請輸入國文成績(-1結束):"))
while score != -1:
chinese_scores.append(score)
score = int(input("請輸入國文成績(-1結束):"))
print(chinese_scores)

要把數值或資料項加入某一個串列中,append方法是最常用的。它的功用是把指定的資料項加到串列的最後端。

執行的結果如下:

請輸入國文成績(-1結束):25
請輸入國文成績(-1結束):65
請輸入國文成績(-1結束):84
請輸入國文成績(-1結束):98
請輸入國文成績(-1結束):48
請輸入國文成績(-1結束):78
請輸入國文成績(-1結束):-1
[25, 65, 84, 98, 48, 78]

把兩個程式結合起來,就可以讓使用者輸入成績,然後計算出總分和平均了。

chinese_scores = list()
score = int(input("請輸入國文成績(-1結束):"))
while score != -1:
chinese_scores.append(score)
score = int(input("請輸入國文成績(-1結束):"))
print("所有輸入的成績:", chinese_scores)
sum = 0
for score in chinese_scores:
sum += score
print("總分:{}分,平均:{:.2f}分".format(sum, sum/10))

串列中的串列

在上述的程式中,我們以list()函數建立一個空的串列,然後透過append()方法函數把資料項目加到某一個指定的串列中。

除了append之外,串列還有許多可以增加、編輯、以及刪除資料項目的方法,同學們可以去網路上查查看喔。

執行的結果如下:

請輸入國文成績(-1結束):95
請輸入國文成績(-1結束):84
請輸入國文成績(-1結束):78
請輸入國文成績(-1結束):85
請輸入國文成績(-1結束):98
請輸入國文成績(-1結束):65
請輸入國文成績(-1結束):84
請輸入國文成績(-1結束):98
請輸入國文成績(-1結束):75
請輸入國文成績(-1結束):-1
所有輸入的成績: [95, 84, 78, 85, 98, 65, 84, 98, 75]
緦分:762分,平均:76.20分

串列厲害的地方不只這樣。傳統程式語言的陣列和串列有些類似,但是它們整個陣列中只能儲存相同型態的資料,但是在串列中並不會去限制你的資料項之型態,所以在同一個串列中可以具有數字,同時也可以放文字,甚至是放一個串列進去。

所以,如果我們的程式要處理的是全班同學的國文、英文、數學三科成績,使用串列的話,可以是如下的型式(假設全班有5位同學):

chinese_scores = [80, 56, 78, 43, 89]
english_scores = [56, 54, 76, 94, 34]
mathematics_scores=[85, 65, 74, 15, 45]
scores = [chinese_scores, english_scores, mathematics_scores]
print(scores)

執行的結果如下所示:

[[80, 56, 78, 43, 89], [56, 54, 76, 94, 34], [85, 65, 74, 15, 45]]

那該如何計算各科的總分和平均呢?如下所示:

subjects = ['國文', '英文', '數學']
chinese_scores = [80, 56, 78, 43, 89]
english_scores = [56, 54, 76, 94, 34]
mathematics_scores=[85, 65, 74, 15, 45]
scores = [chinese_scores, english_scores, mathematics_scores]
for index, subject_scores in enumerate(scores):
sum = 0
for score in subject_scores:
sum += score
print("{}科的總分:{}分,平均:{:.2f}分".format(subjects[index], sum, sum/len(subject_scores)))

在第6行使用enumerate()列舉函數的目的是為了要取得for迴圈中執行程式碼時是處於哪一遍迴圈的執行中。取得的index被用在第10行,用來拿取subjects串列中的科目。我們預設第一遍迴圈處理的是國文科,第二遍是英文科,第三遍是數學科。

執行的結果如下:

國文科的總分:346分,平均:69.20分
英文科的總分:314分,平均:62.80分
數學科的總分:284分,平均:56.80分

上述的程式再結合上由使用者輸入成績的話,整個程式就非常實用了。

串列常用的操作函數

方法函數的概念

我們的程式操作到現在,同學們可能會發現有些物件可以直接在物件的名稱後面使用一些函數的功能,而有一些不行。哪些物件可以使用哪些方法函數,如果不熟悉的話,可以使用dir函數來查詢,以下是操作的過程:

sort

在上面的例子中,變數a是一般的整數物件,而變數b則是一個串列物件。同樣都是使用dir去檢查它們可以使用的方法函數,得到的結果就不太一樣。我們先以len為例來說明。

len

len函數其實並不屬於list,它可以用在大部份的具有多個項目的變數物件上,用來求取該變數的項目數(如果有的話),如同上面的例子,我們分別對變數a和變數b使用len函數試試看。

同學們可以仔細對照一下之前使用dir查詢過的內容就可以發現,一般的變數物件(在此是int)是沒有所謂項數目的概念,因此就沒辦法對它使用len函數以查詢項目數,而變數b是為是list物件,它就有項目數的概念,因此使用len(b)就會傳回它的項目數,在此例為3。

除了len之外,對於串列的操作,還有幾個重要的方法函數可以使用,摘要說明如下:

append

假設把串列看成是一串接在一起的資料項目,那麼這一串的資料項目其實是有前後順序的,愈先加入的就放在愈前面,因此,append(dataitem)的功能除了代表是把資料項目加進串列中之外,被加進去的資料項目也是以放在最後面為主。請參考以下的內容:

>>> b = list()
>>> b.append(2)
>>> b
[2]
>>> b.append(5)
>>> b
[2, 5]
>>> b.append(1)
>>> b
[2, 5, 1]
>>> b.append("Richard")
>>> b
[2, 5, 1, 'Richard']

上述的程式片段示範如何把b這個變數設定為一個空的串列,然後透過append方法函數,逐一把想要的資料項目放到串列中。

reverse

因為串列本身有順序性,因此就會有前後順序的觀念,也因此,就衍生出可以操作資料項目順序的函數,reverse就是這樣的函數,它可以把放進去的資料倒過來放置,如下所示:

>>> b
[2, 5, 1, 'Richard']
>>> b.reverse()
>>> b
['Richard', 1, 5, 2]
>>> b.reverse()
>>> b
[2, 5, 1, 'Richard']

sort方法函數和sorted()

對於串列的內容除了前後順序之外,通常我們也會對於資料內容的大小排列有興趣,要排序資料項目的大小順序有兩個常用的函數,分別是sorted()以及sort(),其中sorted()會傳回排序的結果,但是不會更改原始串列中的內容,而sort()則是直接更改其內容,請參考以下的程式操作:

>>> b = [2, 5, 10, 3, 4, 9]
>>> sorted(b)
[2, 3, 4, 5, 9, 10]
>>> b
[2, 5, 10, 3, 4, 9]
>>> b.sort()
>>> b
[2, 3, 4, 5, 9, 10]
>>> b
[2, 5, 10, 3, 4, 9]
>>> b.sort()
>>> b
[2, 3, 4, 5, 9, 10]
>>> b.sort(reverse=True)
>>> b
[10, 9, 5, 4, 3, 2]
>>> sorted(b)
[2, 3, 4, 5, 9, 10]
>>> sorted(b, reverse=True)
[10, 9, 5, 4, 3, 2]

pop

要取出串列內資料項目的方法除了直接以索引值的方式指定項目之外,如果想要做的是把是後一個資料項取出使用,而且進一步地把該資料項從串列中移除的話,pop是最好用的函數。

>>> b = [10, 9, 5, 4, 3, 2]
>>> b.pop()
2
>>> b
[10, 9, 5, 4, 3]
>>> b.pop(2)
5
>>> b
[10, 9, 4, 3]
>>> b.pop(1)
9
>>> b
[10, 4, 3]

雖說pop的功用是從後面取出並移走資料項,但是當在pop中加入數字之後,該數字就變成是串列的索引值,會依照該索引值來取出並移走資料項,這是要留意的地方。

del、remove以及in運算子

同樣都是移除資料,remove所指定的參數就不是索引值,而是資料項本身,但是,如果指定的資料項目不在,則會產生出錯誤訊息,所以通常在使用remove方法函數的時候,都會搭配in運算子一起使用。

>>> x = [2, 3, 4, 5, 6, 10, 32, 3]
>>> x.remove(3)
>>> x
[2, 4, 5, 6, 10, 32, 3]
>>> x.remove(11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

在上述的例子中,x串列中有2個3,但是使用x.remove(3)只會消除第一個符合的資料項而已。此外,使用remove也不會傳回該移除的資料項,不像是pop會把資料項彈回。

要刪除資料項還有一個del運算子,使用方法如下:

>>> x
[2, 4, 5, 6, 10, 32, 3]
>>> del x[3]
>>> x
[2, 4, 5, 10, 32, 3]

和pop一樣刪除的是索引位置中的資料項,但是並不會傳回值,單純就是把該資料項無聲無息地刪除。

count

有些情況會想要檢查某一筆資料項在串列中出現的次數,此時就很適合使用count方法函數,使用方法如下:

>>> namelist = ["Tom", "Richard", "Kerry", "Mary", "May", "Mary", "Tom", "Tom", "Lisa"]
>>> namelist.count("Tom")
3
>>> namelist.count("Judy")
0