Groovy中Map简介
1. 概述
Groovy 扩展了Java中的*Map * API以提供过滤、搜索和排序等操作的方法。它还提供了多种创建和操作Map的速记方式。
在本教程中,我们将了解 Groovy 使用Map的方式。
2. 创建 Groovy Map
*我们可以使用Map文字语法[k:v]*来创建Map。**基本上,它允许我们实例化一个映射并在一行中定义条目。 可以使用以下方法创建空Map:
def emptyMap = [:]
同样,可以使用以下方法实例化具有值的映射:
def map = [name: "Jerry", age: 42, city: "New York"]
请注意,**键没有被引号包围,并且默认情况下,Groovy 创建了java.util.LinkedHashMap 的一个实例。**我们可以使用as操作符来覆盖这个默认行为。
3. 添加项目
让我们从定义一个Map开始:
def map = [name:"Jerry"]
我们可以向Map添加一个键:
map["age"] = 42
然而,另一种更类似于 Javascript 的方式是使用属性表示法(点运算符):
map.city = "New York"
换句话说,Groovy 支持以类似 bean 的方式访问键值对。
在向Map添加新项目时,我们还可以使用变量而不是文字作为键:
def hobbyLiteral = "hobby"
def hobbyMap = [(hobbyLiteral): "Singing"]
map.putAll(hobbyMap)
assertTrue(hobbyMap.hobby == "Singing")
assertTrue(hobbyMap[hobbyLiteral] == "Singing")
首先,我们必须创建一个存储关键hobby的新变量。然后我们使用括号中的这个变量和映射文字语法来创建另一个映射。
4. 检索项目
文字语法或属性表示法可用于从Map中获取项目。
对于定义为的Map:
def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]
我们可以得到key对应的值:
assertTrue(map["name"] == "Jerry")
或者
assertTrue(map.name == "Jerry")
5. 移除项目
我们可以使用*remove()方法根据键从映射中删除任何条目,但**有时我们可能需要从映射中删除多个条目。我们可以通过使用minus()方法来做到这一点。*
minus()方法接受一个Map并在从底层映射中删除给定映射的所有条目后 返回一个新map:
def map = [1:20, a:30, 2:42, 4:34, ba:67, 6:39, 7:49]
def minusMap = map.minus([2:42, 4:34]);
assertTrue(minusMap == [1:20, a:30, ba:67, 6:39, 7:49])
接下来,我们还可以根据条件删除条目。我们可以使用*removeAll()*方法实现这一点:
minusMap.removeAll{it -> it.key instanceof String}
assertTrue(minusMap == [1:20, 6:39, 7:49])
相反,要保留所有满足条件的条目,我们可以使用*retainAll()*方法:
minusMap.retainAll{it -> it.value % 2 == 0}
assertTrue(minusMap == [1:20])
6. 遍历条目
*我们可以使用*each()和eachWithIndex()方法遍历条目 。
each()方法提供隐式参数,如entry、key和 value ,它们对应于当前Entry。
除了Entry之外,*eachWithIndex()*方法还提供了一个索引。这两种方法都接受一个closures 作为参数。
在下一个示例中,我们将遍历每个entry。传递给each()方法的closures从隐式参数条目中获取键值对并打印出来:
map.each{entry -> println "$entry.key: $entry.value"}
接下来,我们将使用*eachWithIndex()*方法打印当前索引以及其他值:
map.eachWithIndex{entry, i -> println "$i $entry.key: $entry.value"}
也可以要求单独提供key、value和 index :
map.eachWithIndex{key, value, i -> println "$i $key: $value"}
7. 过滤
**我们可以使用find()、findAll()和grep()方法根据键和值过滤和搜索映射条目。
让我们首先定义一个Map来执行这些方法:
def map = [name:"Jerry", age: 42, city: "New York", hobby:"Singing"]
首先,我们看一下*find()方法,它接受一个Closure 并返回第一个匹配Closure 条件的Entry *:
assertTrue(map.find{it.value == "New York"}.key == "city")
类似地,findAll 也接受一个Closure , 但返回一个包含所有满足Closure 条件的键值对的Map:
assertTrue(map.findAll{it.value == "New York"} == [city : "New York"])
如果我们更喜欢使用List,我们可以使用 grep而不是 findAll:
map.grep{it.value == "New York"}.each{it -> assertTrue(it.key == "city" && it.value == "New York")}
我们首先使用 grep 查找具有值 New York 的条目。然后,为了演示返回类型是List,我们将遍历grep() 的结果。对于隐式参数中可用的列表中的每个*Entry *,我们将检查其是否为预期结果。
接下来,要确定Map中的所有项目是否满足条件,我们可以使用every, 它返回一个boolean。
让我们检查一下Map中的所有值是否都是String类型:
assertTrue(map.every{it -> it.value instanceof String} == false)
同样,我们可以使用any来确定Map中的任何项目是否符合条件:
assertTrue(map.any{it -> it.value instanceof String} == true)
8. 转化与收集
有时,我们可能希望将映射中的条目转换为新值。使用collect()和collectEntries()方法,可以将条目分别转换和收集到Collection或Map 中。
让我们看一些例子。给定一张员工 ID 和员工的Map:
def map = [
1: [name:"Jerry", age: 42, city: "New York"],
2: [name:"Long", age: 25, city: "New York"],
3: [name:"Dustin", age: 29, city: "New York"],
4: [name:"Dustin", age: 34, city: "New York"]]
我们可以使用*collect()*将所有员工的姓名收集到一个列表中:
def names = map.collect{entry -> entry.value.name}
assertTrue(names == ["Jerry", "Long", "Dustin", "Dustin"])
然后,如果我们对一组唯一的名称感兴趣,我们可以通过传递一个Collection对象来指定集合:
def uniqueNames = map.collect([] as HashSet){entry -> entry.value.name}
assertTrue(uniqueNames == ["Jerry", "Long", "Dustin"] as Set)
如果我们想将Map中的员工姓名从小写更改为大写,我们可以使用collectEntries。此方法返回转换值的映射:
def idNames = map.collectEntries{key, value -> [key, value.name]}
assertTrue(idNames == [1:"Jerry", 2:"Long", 3:"Dustin", 4:"Dustin"])
最后,还可以将collect方法与find和findAll方法结合使用来转换过滤结果:
def below30Names = map.findAll{it.value.age < 30}.collect{key, value -> value.name}
assertTrue(below30Names == ["Long", "Dustin"])
在这里,我们将找到所有年龄在 20-30 岁之间的员工,并将他们收集到一张Map中。
9. 分组
有时,我们可能希望根据条件将Map的某些项目分组为子Map。
**groupBy()方法返回一个映射映射,每个映射包含键值对,对于给定条件,它们的计算结果相同:
def map = [1:20, 2: 40, 3: 11, 4: 93]
def subMap = map.groupBy{it.value % 2}
assertTrue(subMap == [0:[1:20, 2:40], 1:[3:11, 4:93]])
**创建子图的另一种方法是使用subMap()。**它与*groupBy()*的不同之处在于它只允许基于键进行分组:
def keySubMap = map.subMap([1,2])
assertTrue(keySubMap == [1:20, 2:40])
在这种情况下,键 1 和 2 的条目将在新映射中返回,而所有其他条目都将被丢弃。
10. 排序
通常在排序时,我们可能希望根据键或值或两者对映射中的条目进行排序。Groovy 提供了可用于此目的的*sort()*方法。
给定一个Map:
def map = [ab:20, a: 40, cb: 11, ba: 93]
如果需要对键进行排序,我们将使用基于自然排序的无参数*sort()*方法:
def naturallyOrderedMap = map.sort()
assertTrue([a:40, ab:20, ba:93, cb:11] == naturallyOrderedMap)
或者我们可以使用*sort(Comparator)*方法来提供比较逻辑:
def compSortedMap = map.sort({k1, k2 -> k1 <=> k2} as Comparator)
assertTrue([a:40, ab:20, ba:93, cb:11] == compSortedMap)
接下来,*要对键、值或两者进行排序,我们可以为*sort()提供闭包条件:
def cloSortedMap = map.sort({it1, it2 -> it1.value <=> it1.value})
assertTrue([cb:11, ab:20, a:40, ba:93] == cloSortedMap)