開源技術教學文件網 建立和使用串列 (List)

最後修改日期為 FEB 14, 2019

陣列 vs. 串列

Groovy 的串列在 Java 中其實對應三種容器 (或資料結構):

  • 陣列 (array)
  • 動態陣列 (dynamic array),相當於 java.util.ArrayList
  • 連結串列 (linked list),相當於 java.util.LinkedList

在 Groovy 中,使用這三種容器的語法大部分是相同的,所以要知道其內部實作的差異。

連結串列內部以不在記憶體中不連續的節點來相連:

連結串列

由於節點間不連續,新增和移除節點相對容易,只要配置節點的記憶體後將該節點和相鄰節點連結即可。但要以索引 (index) 隨機存取節點的值就不方便,因為要逐一走訪這些節點。

相對來說,陣列內部則是連續配置且緊密排列的節點:

陣列

由於節點間緊密排列,以索引隨機存取的效率相當好。但是,要新增或移除節點就很不方便,要先配置一塊夠大的陣列後,再將陣列元素逐一搬動。

兩種容器各有優缺點,要視當下的情境去選擇。有關陣列和串列的討論和比較可看一些資料結構的資料。

建立串列

以下例子建立串列實字 (list literal),存取其大小和其中的元素:

def list = [1, 2, 3]

assert list.size() == 3
assert list[0] == 1

串列以數字為索引 (index),從零開始計算 (zero-based)。

在預設情形下,Groovy 的串列是 ArrayList。但我們可以使用 as 指定串列的型別:

def list = [5, 6, 7, 8] as java.util.LinkedList

// Use list as before.
assert list.size() == 4
assert list[0] == 5

// Now list is a `java.util.LinkedList`
assert list instanceof java.util.LinkedList

這時候串列是 LinkedList

存取串列元素

除了基本的以索引存取元素外,Groovy 提供一些語法糖來存取串列元素,參考下例:

def list = ["a", "b", "c", "d", "e", "f"]

// Retrieve sublist
assert list[0..2] == ["a", "b", "c"]
assert list[0,2,4] == ["a", "c", "e"]

// Replace sublist with another sublist
list[0..2] = ["x", "y", "z"]

assert list == ["x", "y", "z", "d", "e", "f"]

// Remove sublist
list -= list[3..5]
assert list == ["x", "y", "z"]

// Insert sublist
list[1..1] = [0, 1, 2]
assert list == ["x", 0, 1, 2, "z"]

如果覺得這些語法糖過於花俏,不一定要使用,也可以用比較基本的方式來寫。

走訪串列

在 Groovy 中,可透過 for 迴圈或迭代器 (iterator) 走訪元素。下例使用 for 搭配迭代器:

final list = ("a" .. "e").toList()

for (e in list) {
    println e
}

list.each { println it }

必要時,也可用傳統的 C 風格 for 迴圈來走訪:

final list = ("a" .. "e").toList()

for (def i = 0; i < list.size(); i++) {
    println list[i]
}

以下範例則是直接用串列的迭代器來走訪:

[5, 6, 7, 8].each {
    println it
}

Groovy 的語法比較多元,選擇最符合當下語境的即可。

利用高階函式操作串列

以下的例子進行一系列串列的操作:

def n = (1..10).toList()
    .findAll { it % 2 != 0 }
    .collect { it ** 2 }
    .inject(0) { a, b -> a + b }

assert n == 1 ** 2 + 3 ** 2 + 5 ** 2 + 7 ** 2 + 9 ** 2

在這個例子,短短數行程式就進行了數項串列的操作。一開始時,先將 1..10 的 range 轉串列,再用 findAll 留下符合條作的元素,再用 collect 將這些元素逐一轉換,最後用 inject 將這些元素以相加合併。這算是高階函式 (higher-order function) 的應用,一開始看不懂不用太勉強。

分享本文
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Yahoo
追蹤本站
Facebook Facebook Twitter