跳轉到內容

列表處理

來自華夏公益教科書,開放書籍,構建開放世界

論文2 - ⇑ 函數語言程式設計基礎 ⇑

← 函數語言程式設計基礎 列表處理 高階函式 →



列表 - 一種抽象資料型別,按特定順序儲存專案。


列表是一種 抽象資料型別,按特定順序儲存專案。同一個專案可以在同一個列表中出現多次。例如,以下都是列表

[9,2,3,4,4,3,7,8]

[65,75,3,65,0]

["cabbage", "potato", "boat", "helmet", "boat"]

空列表由空括號定義

[]

列表也可以包含其他列表

[[1,2,3], [6,3,8], [9,10,3]]

在 Haskell 中,列表中包含的專案必須都是同一資料型別。

擴充套件:資料型別和列表

雖然像 Haskell 這樣的某些程式語言只允許列表中的專案為同一資料型別,但有時可以在列表中包含多種資料型別。雖然這可能可行,但可能不是一個好主意,並且會導致一些非常難以除錯的程式碼。例如,在 python 中,我們可能從一些看起來非常簡單的程式碼中得到意外的輸出

.> myList = ['-92', 9, 5]
.> min(myList)
5


建立和檢查列表

[編輯 | 編輯原始碼]

您可以在列表上執行一系列函式

您可以建立一個空列表

.> someList = []
.> someList
[]

您可以建立一個包含專案的列表

myList = [20,3,51,6,3,7]

您可以獲取列表的長度

.> myList = [20,3,51,6,3,7]
.> length myList
6

您可以檢查列表是否為空

.> myList = [20,3,51,6,3,7]
.> null myList
False

.> someList = []
.> null myList
True

拆分列表

[編輯 | 編輯原始碼]
頭部 - 列表中的第一個元素。


尾部 - 列表中除頭部之外的每個元素。


一些非常常見的列表命令是頭部尾部。如果您將列表視為一條蛇,頭部將為您提供列表中的第一個專案(它的頭部),而尾部將刪除蛇的頭部,並將剩下的部分作為新列表返回。

snake analogy for traversing a list
遍歷列表的蛇類比喻
.> myList = [20,3,51,6,3,7]
.> head(myList)
20
.> myList = [20,3,51,6,3,7]
.> tail(myList)
[3, 51, 6, 3, 7]

您可以將多個頭部和尾部命令組合在一起

.> myList = [20,3,51,6,3,7]
.> head(tail(tail(myList)))
51
示例:組合多個頭部和尾部命令

在上面的示例中,我們從最裡面的函式開始,在本例中是tail(...),並向外逐步進行。

head(tail(tail(myList)))

命令tail(myList)會從myList中刪除第一個專案,並返回剩下的部分:[3,51,6,3,7]。然後,我們可以用此返回的列表替換tail(myList)

head(tail([3,51,6,3,7]))

現在我們進入下一個最裡面的函式

head(tail([3,51,6,3,7]))

命令tail([3,51,6,3,7])會從[3,51,6,3,7]中刪除第一個專案,並返回剩下的部分:[51,6,3,7]。然後,我們可以用此返回的列表替換tail([3,51,6,3,7])

head([51,6,3,7])

這隻剩下一個函式要計算了。我們知道head函式會返回給定列表的第一個專案。在本例中,它獲取[51,6,3,7]的第一個專案,得到

51

向列表新增元素

[編輯 | 編輯原始碼]

前置 (:) 一個專案到另一個列表,即在前面新增一個元素,向列表新增一個新的頭部

.> myList = [20,3,51,6,3,7]
.> 5 : myList
[5, 20, 3, 51, 6, 3, 7]
.> "c" : ["a", "t"]
["c", "a", "t"]
.> 1 : 2 : myList
[1, 2, 20, 3, 51, 6, 3, 7]
擴充套件:處理字串、字元和列表時的型別不匹配

您可能習慣於其他程式語言以幾乎相同的方式處理單引號和雙引號,例如在 Javascript 中

.> a = "Double quotation marks with a single (') in the middle"
.> b = 'Single quotation marks with a double (") in the middle'
.> a == b
True

Haskell 並非如此。Haskell 將單引號 (') 視為定義單個元素,而將雙引號 (") 視為定義一個列表,即使雙引號內只有一個元素,例如 "c"。這意味著它將 'c' 視為一個型別為 Char 的單個專案,而將 "c" 視為一個型別為 Char列表。如果我們確保匹配我們的資料型別,我們將沒問題。

['c', 'a', 't'] 等效於 "cat"

.> "cat"
"cat"
.> ['c','a','t']
"cat"
.> ['c','a','t'] == "cat"
True

["c", "a", "t"] 等效於 "cat",因為 ["c", "a", "t"] 是一個型別為 Char列表的列表,而 "cat" 是一個型別為 Char 的列表。當嘗試以下操作時,我們可以看到這種不匹配

.> ["c","a","t"] == "cat"
error:
* Couldn't match type `Char' with `[Char]'
  Expected type: [[Char]]
  Actual type: [Char]

我們可以看到 ["c", "a", "t"] 是一個型別為 Char列表的列表,方法是:

.> ["c","a","t"] == [['c'],['a'],['t']]
True

列表 "c" 前置到列表 ["a", "t"] 很好,因為前置專案的型別(型別為 Char列表)與它所前置到的列表項的型別匹配,即型別為 Char 的列表

.> "c" : ["a", "t"]
["c", "a", "t"]

當將型別為 Char 的專案 'c' 前置到型別為 Char 的列表 ['a', 't'] 時,我們也可以這樣做

.> 'c' : ['a', 't']
"cat"

但嘗試將型別為 Char 的專案 'c' 前置到型別為 List Char 的列表 ["a", "t"] 將不起作用。此處的錯誤訊息顯示了型別 Char 和型別為 Char列表之間的區別,在錯誤訊息中由 [Char] 定義

.> 'c' : ["a", "t"]
* Couldn't match expected type `Char' with actual type `[Char]'
* In the expression: "a"
  In the second argument of `(:)', namely `["'a", "t"]'
  In the expression: 'c' : ["'a", "t"]

追加 (++) 一個專案或列表到另一個列表,即在末尾新增某些內容,可能是一個專案或另一個列表

.> myList = [20,3,51,6,3,7]
.> myList ++ 99
[20, 3, 51, 6, 3, 7, 99]
.> myList ++ [5, 4, 3, 2]
[20, 3, 51, 6, 3, 7, 5, 4, 3, 2]

前置命令 (:) 只能允許您將單個元素新增到列表的前面。如果您想將一個列表新增到另一個列表的前面,您可以使用追加 (++) 命令

.> listA = ["x", "y", "z"]
.> listB = ["d", "c"]
.> listA ++ ["e"]
["x", "y", "z", "e"]
.> listA ++ listB
["x", "y", "z", "d", "c"]

您可以使用追加和前置的組合來組合多個列表和專案

.> "hello" ++ " " ++ "world"
"hello world"
.> '!' : "shocking" ++ "this" ++ ['w', 'o', 'r', 'k', 's'] ++ "!"
"!shockingthisworks!"
練習:列表

以下 Haskell 程式碼輸出什麼

myList = [3,4,5,3,4,6]
head(tail(tail(myList)))

答案

5


以下 Haskell 程式碼輸出什麼

myList = ['a', 'b', 'c', 'd']
tail(myList)

答案

['b', 'c', 'd'] 或 "bcd"


以下 Haskell 程式碼輸出什麼

myList = ["cat", "mouse", "moose", "cow", "sheep"]
length(tail(tail(tail(myList))))

答案

2


以下 Haskell 程式碼輸出什麼

myList = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
null(head(tail(tail(myList))))
length(tail(head(tail(tail(myList ++ ["black", "white"])))))

答案


錯誤
5

請注意,當我們獲取包含字串的單個元素列表的尾部時,它會將字串視為一個列表。


給定一個名為 containsPrime 的列表,其值為 [6,8,9,7,15,21],僅使用頭部和尾部命令,編寫一些 Haskell 程式碼來返回數字 7

答案


head(tail(tail(tail(containsPrime))))



給定一個名為 someList 的列表,其值為 ["badger", "fish", "vole"],僅使用 headtail 和追加 (++) 命令,編寫一些 Haskell 程式碼來返回列表 ["vole", "frog"]

答案


let someList = ["badger", "fish", "vole"]
tail(tail(someList ++ ["frog"]))


以下程式碼做什麼

.> listA = [1, 2, 3]
.> listB = [9, 8]
.> listA ++ tail(listB)
.> tail(tail(listA) ++ tail(listB))

答案


[1,2,3,8]
[3,8]


以下程式碼做什麼

.> listA = ['o', 'x', 'p', 'e']
.> 'r' : [head(listA)] ++ tail(tail(listA))

答案


"vape" 或者 ['r', 'o', 'p', 'e']


華夏公益教科書