Groovy 列表
最后修改于 2025 年 3 月 20 日
Groovy 中的列表是动态集合,可以增长或收缩,不像数组。它们功能多样,支持添加、移除、排序和过滤等各种操作。本教程将通过实用示例探索列表的创建和操作,以阐明每个概念。
创建列表
列表使用方括号创建,可以轻松地用任何类型的初始值进行初始化,为数据提供了灵活的起点。
def nums = [1, 2, 3] def words = ['cat', 'dog'] println nums println words
nums 存储整数,words 存储字符串,两者都用 [] 定义。这种语法很直观,列表可以混合类型或保持统一,根据您的需求进行调整,无需严格的类型限制。
空列表
您可以从空列表开始,以后再填充它,这在程序执行期间动态添加数据时非常有用。
def list = [] list << 1 list << 'two' println list
[] 创建一个空列表。<< 操作符用于追加元素,这里添加了一个数字和一个字符串。这展示了列表的增长能力和轻松处理混合类型的功能。
大小/最大/最小
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() }
min 和 max 分别在 vals 中查找最小值和最大值,即 -1 和 5。size 返回计数,即 7。对于 words,min { it.size() } 查找“at”(最短,2 个字母),max { it.size() } 查找“universe”(最长,8 个字母)。闭包允许您定义“最小”或“最大”的含义,从而增强了 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 在列表处理方面的简洁而强大的方法。
清空/是否为空
您可以检查列表是否为空或清空其内容,从而在运行时控制其状态,这对于重置或验证非常有用。
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)。empty 和 isEmpty 都有效,但 isEmpty 更明确;clear 展示了列表的可变性。
类型
Groovy 列表默认为 java.util.ArrayList 的实例,您可以验证其类型或检查其类进行调试或逻辑判断。
def vals = [2, 3, 4, 5] println vals.getClass() println vals instanceof List
getClass 返回 java.util.ArrayList,这是底层实现。instanceof List 确认 vals 是 List 类型(true)。这反映了 Groovy 使用 Java 的集合,同时增加了自己的语法糖,这对于类型检查或互操作性很有用。
第一个/最后一个,头部/尾部/初始
列表提供了访问其末尾或将其拆分为部分的方法,提供了快速获取特定元素或子部分的方式。
def vals = [1, 2, 3, 4, 5] println vals.first() println vals.head() println vals.last() println vals.tail() println vals.init()
first 和 head 都返回 1,即第一个元素。last 返回 5,即最后一个元素。tail 返回第一个元素之后的所有元素([2, 3, 4, 5]),init 返回最后一个元素之前的所有元素([1, 2, 3, 4])。这些方法简化了列表末端的处理,无需索引,提高了可读性。
索引/获取
通过索引或 get 方法访问列表元素,并支持范围和负索引以进行灵活检索。
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) 模仿方括号表示法,但基于方法,提供了替代的访问语法。
添加/移除
列表是可变的,允许您使用各种方法和操作符动态添加或移除元素,以满足不同的需求。
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 方法根据指定的大小将列表分割成子列表,这对于将数据划分为可管理的数据块很有用。
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 表示“其余部分”)。此方法返回一个列表的列表,保留原始顺序。
修改
列表可以通过用于添加、移除和替换元素的各种方法进行就地修改,让您可以精细地控制其内容。
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 交换第一个和最后一个元素,展示了多种动态修改列表的方式。
加/减
plus 和 minus 操作符组合或减去元素,创建新列表而不改变原始列表,这对于构建或过滤非常理想。
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 方法完成,提供了灵活性和选项,例如反转顺序以满足不同的遍历需求。
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 的现代风格。
排序
排序会重新排列列表元素,可以是就地修改,也可以是通过闭包进行自定义逻辑,从而控制顺序和方向以满足各种用例。
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 } 使用三元运算符显式进行升序排序。对于 words,sort 按字母顺序排序,sort { b <=> a } 则反转顺序。排序是就地进行的,直接修改列表。
反转
反转会颠倒列表的顺序,可以选择创建副本或就地修改,这取决于您是否需要原始列表,从而为您提供灵活性。
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 根据条件或类型过滤列表,返回一个包含匹配元素的新列表,这对于选择性提取非常理想。
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 方法移除重复项,可以是创建副本或就地修改,这对于清理冗余数据很有用。
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,移除重复项。布尔参数控制操作是否具有破坏性,根据您的需求提供选项。
计数
计数方法统计特定值或条件的出现次数,无需手动循环即可快速了解列表内容。
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)。这些方法同时提供精确计数和条件计数,增强了数据分析能力。
洗牌
洗牌会随机化列表的顺序,可以选择创建副本或就地修改,这对于随机抽样或重新排序任务很有用。
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 将嵌套列表转换为单层列表,简化复杂结构,以便于处理或显示。
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 交互非常有用。
def cmds = ['ls', '-l'].execute() cmds.waitFor() println cmds.text
['ls', '-l'].execute 执行“ls -l”(Unix 目录列表;Windows 上使用“dir”)。waitFor 确保命令完成,text 输出结果。这使得 Groovy 可以与操作系统进行交互,尽管输出因系统而异 — 此处,它是类 Unix 行为的占位符。
来源
本教程通过实用示例探讨了 Groovy 列表。
作者
列出 所有 Groovy 教程。