ZetCode

Groovy 列表

最后修改于 2025 年 3 月 20 日

Groovy 中的列表是动态集合,可以增长或收缩,不像数组。它们功能多样,支持添加、移除、排序和过滤等各种操作。本教程将通过实用示例探索列表的创建和操作,以阐明每个概念。

创建列表

列表使用方括号创建,可以轻松地用任何类型的初始值进行初始化,为数据提供了灵活的起点。

CreateList.groovy
def nums = [1, 2, 3]
def words = ['cat', 'dog']
println nums
println words

nums 存储整数,words 存储字符串,两者都用 [] 定义。这种语法很直观,列表可以混合类型或保持统一,根据您的需求进行调整,无需严格的类型限制。

空列表

您可以从空列表开始,以后再填充它,这在程序执行期间动态添加数据时非常有用。

EmptyList.groovy
def list = []
list << 1
list << 'two'
println list

[] 创建一个空列表。<< 操作符用于追加元素,这里添加了一个数字和一个字符串。这展示了列表的增长能力和轻松处理混合类型的功能。

大小/最大/最小

Groovy 列表提供了一些方法来查找它们的大小和极端值,并使用闭包进行可自定义的比较,以增加灵活性。

ListSizeMaxMin.groovy
def vals = [-1, 0, 1, 2, 3, 4, 5]

println vals.min()
println vals.max()
println vals.size()

def words = ['sky', 'at', 'storm', 'falcon', 'universe']
println words.min { it.size() }
println words.max { it.size() }

minmax 分别在 vals 中查找最小值和最大值,即 -1 和 5。size 返回计数,即 7。对于 wordsmin { it.size() } 查找“at”(最短,2 个字母),max { it.size() } 查找“universe”(最长,8 个字母)。闭包允许您定义“最小”或“最大”的含义,从而增强了 Groovy 的功能。

平均值/计数/总和

列表支持数值运算,如平均值计算、基于条件的计数和求和,这使得它们在数据分析任务中非常方便。

ListAvgCountSum.groovy
def vals = [-2, -1, 0, 1, 2, 3, 4]

println vals.average()
println vals.count{ it > 0}
println vals.sum()
println vals.grep(it -> it < 0).sum()

average 计算平均值(此处为 1),count{ it > 0} 统计正数(4 个),sum 将所有元素相加(7)。grep(it -> it < 0).sum 先过滤负数再将它们相加(-3)。这些方法利用了闭包和链式调用,展示了 Groovy 在列表处理方面的简洁而强大的方法。

清空/是否为空

您可以检查列表是否为空或清空其内容,从而在运行时控制其状态,这对于重置或验证非常有用。

ListClearEmpty.groovy
def vals = [-2, -1, 0, 1, 2, 3, 4]

if (vals.empty) {
    println "list is empty"
} else {
    println "list is not empty"
}

vals.clear()

if (vals.isEmpty()) {
    println "list is empty"
} else {
    println "list is not empty"
}

最初,vals.empty 检查 vals 是否为空(false,因为它有 7 个元素)。在 clear 移除所有元素后,isEmpty 确认它是空的(true)。emptyisEmpty 都有效,但 isEmpty 更明确;clear 展示了列表的可变性。

类型

Groovy 列表默认为 java.util.ArrayList 的实例,您可以验证其类型或检查其类进行调试或逻辑判断。

ListType.groovy
def vals = [2, 3, 4, 5]

println vals.getClass()
println vals instanceof List

getClass 返回 java.util.ArrayList,这是底层实现。instanceof List 确认 valsList 类型(true)。这反映了 Groovy 使用 Java 的集合,同时增加了自己的语法糖,这对于类型检查或互操作性很有用。

第一个/最后一个,头部/尾部/初始

列表提供了访问其末尾或将其拆分为部分的方法,提供了快速获取特定元素或子部分的方式。

ListFirstLast.groovy
def vals = [1, 2, 3, 4, 5]

println vals.first()
println vals.head()

println vals.last()

println vals.tail()
println vals.init()

firsthead 都返回 1,即第一个元素。last 返回 5,即最后一个元素。tail 返回第一个元素之后的所有元素([2, 3, 4, 5]),init 返回最后一个元素之前的所有元素([1, 2, 3, 4])。这些方法简化了列表末端的处理,无需索引,提高了可读性。

索引/获取

通过索引或 get 方法访问列表元素,并支持范围和负索引以进行灵活检索。

ListIndexGet.groovy
def vals = [-2, -1, 0, 1, 2, 3, 4, 5]

println vals[0]
println vals[1]
println vals[-1]
println vals[-2]

println '-------------------'

println vals[0..3]
println vals[3..-1]
println vals[0, 2, 5]
println vals[-2..-5]

println '-------------------'

println vals.get(0)
println vals.get(1)
println vals.getAt(-1)
println vals.getAt(-2)

vals[0] 获取 -2,vals[-1] 获取 5(最后一个),vals[0..3] 切片为 [-2, -1, 0, 1],vals[0, 2, 5] 选择特定索引([-2, 0, 3])。负范围如 -2..-5 从后往前计数([4, 3, 2, 1])。get(0)getAt(-1) 模仿方括号表示法,但基于方法,提供了替代的访问语法。

添加/移除

列表是可变的,允许您使用各种方法和操作符动态添加或移除元素,以满足不同的需求。

ListAddRemove.groovy
def vals = [2, 3, 4, 5]

vals.add(6)
vals << 7
vals << 8 << 9 << 10

vals.add(0, 1)
vals.add(0, 0)
vals.add(0, -1)

println vals
println "-------------------"

vals.remove(vals.size()-1)
vals.remove(0)

println vals

add(6) 追加 6,<< 添加 7,然后链接 8、9、10。add(0, 1) 在索引 0 处插入 1,将其他元素向右移。添加后,remove(size()-1) 删除最后一个元素(10),remove(0) 删除第一个元素(-1)。<< 操作符简洁,而 add 提供了位置控制。

分块

chop 方法根据指定的大小将列表分割成子列表,这对于将数据划分为可管理的数据块很有用。

ListChopping.groovy
def vals = [-2, -1, 0, 0, 1, 1, 2, 3, 4, 4, 4, 5, 6, 4]

println vals.chop(5)
println vals.chop(5, 6)
println vals.chop(2, 3, -1)

chop(5) 获取前 5 个元素,留下其余部分。chop(5, 6) 将列表分成一个 5 个元素的列表和一个 6 个元素的列表,其余部分分开。chop(2, 3, -1) 获取 2 个,然后 3 个,然后所有剩余的(-1 表示“其余部分”)。此方法返回一个列表的列表,保留原始顺序。

修改

列表可以通过用于添加、移除和替换元素的各种方法进行就地修改,让您可以精细地控制其内容。

ListModify.groovy
def vals = [3, 4, 5, 6, 7]

println vals

vals.add(8)
vals << 9 << 10
vals.addAll([11, 12])

println '--------------------------'

vals.pop()
vals.push(0)

println vals

println '--------------------------'

vals[1] = 2

println vals

println '--------------------------'

vals.removeAt(3)
vals.swap(0, vals.size()-1)

println vals

从 [3, 4, 5, 6, 7] 开始,add<<addAll 扩展了它。pop 移除最后一个元素(12),push(0) 在开头添加 0。vals[1] = 2 将 4 替换为 2。removeAt(3) 删除第四个元素,swap 交换第一个和最后一个元素,展示了多种动态修改列表的方式。

加/减

plusminus 操作符组合或减去元素,创建新列表而不改变原始列表,这对于构建或过滤非常理想。

ListPlusMinus.groovy
def vals = [3, 4]
def res = vals.plus(5).plus([6, 7]).plus(8..11)

println vals
println res

def res2 = res.minus(4).minus(5).minus([6, 7]).minus(8..10)

println res2

plus 将 5、然后 [6, 7]、然后范围 [8, 9, 10, 11] 追加到 vals,创建一个新列表。minus 从该结果中移除 4、5、[6, 7] 和 [8, 9, 10],留下 [3, 11]。原始的 vals 保持 [3, 4],这表明这些操作是非破坏性的。

循环

迭代列表可以通过传统循环或 Groovy 的 each 方法完成,提供了灵活性和选项,例如反转顺序以满足不同的遍历需求。

ListLoop.groovy
def words = ['cup', 'crisp', 'cloud', 'break', 
    'falcon', 'war', 'oil']

for (def word in words) {
    println word
}

println "----------------------"

words.each { word -> println word }

println "----------------------"

words.reverseEach { word -> println word }

for 循环按顺序打印每个单词。each 使用闭包执行相同的操作,提供了一种函数式风格。reverseEach 则反向打印,从“oil”到“cup”。这些方法满足了不同的偏好,each 变体为迭代增加了 Groovy 的现代风格。

排序

排序会重新排列列表元素,可以是就地修改,也可以是通过闭包进行自定义逻辑,从而控制顺序和方向以满足各种用例。

ListSorting.groovy
def nums = [ 7, 9, 3, -2, 8, 1, 0 ]
def words = [ "sky", "cloud", "atom", "brown", "den", "kite", "town" ]

nums.sort()
println nums

nums.sort { -it }
println nums

nums.sort { a, b -> a <=> b }
println nums

println "--------------------------------------------"

words.sort()
println words

words.sort { a, b -> b <=> a }
println words

nums 上的 sort 按升序排序 [-2, 0, 1, 3, 7, 8, 9]。sort { -it } 通过否定值进行降序排序。sort { a, b -> a <=> b } 使用三元运算符显式进行升序排序。对于 wordssort 按字母顺序排序,sort { b <=> a } 则反转顺序。排序是就地进行的,直接修改列表。

反转

反转会颠倒列表的顺序,可以选择创建副本或就地修改,这取决于您是否需要原始列表,从而为您提供灵活性。

ListReversing.groovy
def vals = [1, 2, 3, 4, 5, 6]

println vals.reverse()
println vals

println '-----------------------'

vals.reverse(true)
println vals

println '-----------------------'

Collections.reverse(vals)
println vals

reverse 返回一个新列表 [6, 5, 4, 3, 2, 1],vals 保持不变。reverse(true)vals 就地修改为 [6, 5, 4, 3, 2, 1]。Collections.reverse(vals) 执行相同的操作,将其翻转回来。布尔标志或 Java 的 Collections 提供了处理反转的不同方法。

Grep

grep 根据条件或类型过滤列表,返回一个包含匹配元素的新列表,这对于选择性提取非常理想。

ListGrep.groovy
def vals = [-2, -1, 0, 1, 2, 3, 4, 5]

def r1 = vals.grep { it > 0 }
println r1

def some = [1, true, -4, "falcon", 3.4]

def r2 = some.grep(Number)
println r2

grep { it > 0 }vals 中保留正数,返回 [1, 2, 3, 4, 5]。在 some 中,grep(Number) 过滤数字类型,得到 [1, -4, 3.4]。grep 可以使用闭包或类型检查,使其既可以进行条件过滤,也可以进行类型过滤,而且不会更改原始列表。

唯一值

unique 方法移除重复项,可以是创建副本或就地修改,这对于清理冗余数据很有用。

ListUnique.groovy
def vals = [2, 2, -1, -2, 0, 1, 1, 2, -3, 11, 3, 4]

def uniq = vals.unique(false)
println uniq
println vals 

println '-----------------------'

vals.unique(true)
println vals 

unique(false) 返回一个新列表 [-2, -1, 0, 1, 2, -3, 11, 3, 4],vals 保持不变。unique(true) 就地修改 vals,移除重复项。布尔参数控制操作是否具有破坏性,根据您的需求提供选项。

计数

计数方法统计特定值或条件的出现次数,无需手动循环即可快速了解列表内容。

ListCounting.groovy
def vals = [-2, -1, 0, 0, 1, 1, 2, 3, 4, 4, 4, 5, 6, 4]

println vals.count(0)
println vals.count(4)
println vals.count(6)
println vals.count { it > 0 }
println vals.countBy { it < 0}

count(0) 找到 2 个零,count(4) 找到 4 个四,count(6) 找到 1 个六。count { it > 0 } 计算正数(8 个),countBy { it < 0 } 按条件映射计数(true: 2,false: 12)。这些方法同时提供精确计数和条件计数,增强了数据分析能力。

洗牌

洗牌会随机化列表的顺序,可以选择创建副本或就地修改,这对于随机抽样或重新排序任务很有用。

ListShuffle.groovy
def vals = [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]

def shuffled = vals.shuffled()
println shuffled
println vals

println '---------------------------'

vals.shuffle()
println vals

shuffled 返回一个随机化后的新列表,vals 保持不变(每次运行的顺序可能不同)。shuffle 会就地随机化 vals。这两种方法都提供随机性,但 shuffled 保留原始列表,而 shuffle 则直接修改它,以适应不同的场景。

展平

flatten 将嵌套列表转换为单层列表,简化复杂结构,以便于处理或显示。

ListFlatten.groovy
def vals = [1, 2, 3, 4, 5, [6, 7, [8, 9, [10]]]]

println vals
println vals[5]
println vals[5][2]
println vals[5][2][2]
println vals[5][2][2][0]

println vals.flatten()

vals 包含嵌套的子列表。通过索引 vals[5][2][2][0] 可以访问到 10,显示了其深度。flatten 将所有层级解开,得到 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]。它是非破坏性的,返回一个新列表,并且可以处理任意嵌套,这使得它在展平数据方面非常强大。

执行

execute 方法将列表作为系统命令执行,将元素视为命令及其参数,这对于 shell 交互非常有用。

ListExecute.groovy
def cmds = ['ls', '-l'].execute()
cmds.waitFor()

println cmds.text

['ls', '-l'].execute 执行“ls -l”(Unix 目录列表;Windows 上使用“dir”)。waitFor 确保命令完成,text 输出结果。这使得 Groovy 可以与操作系统进行交互,尽管输出因系统而异 — 此处,它是类 Unix 行为的占位符。

来源

Groovy 文档

本教程通过实用示例探讨了 Groovy 列表。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我自 2007 年起撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有八年以上的经验。

列出 所有 Groovy 教程