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 教程。