Groovy 具有在闭包中创建的默认值的映射

Groovy 具有在闭包中创建的默认值的映射,groovy,Groovy,我想将对象存储在地图中(称为结果)。对象是从SQL行创建或更新的。 对于我阅读的每一行,我访问地图如下: def result = [:] sql.eachRow('SELECT something') { row-> { // check if the Entry is already existing def theEntry = result[row.KEY] if (theEntry == null) { // create the entr

我想将对象存储在地图中(称为结果)。对象是从SQL行创建或更新的。 对于我阅读的每一行,我访问地图如下:

def result = [:]
sql.eachRow('SELECT something') { row->
{
    // check if the Entry is already existing
    def theEntry = result[row.KEY]
    if (theEntry == null) {
        // create the entry
        theEntry = new Entry(row.VALUE1, row.VALUE2)

        // put the entry in the result map
        result[row.KEY] = theEntry
    }

    // use the Entry (create or update the next hierarchie elements)
}
我想最小化检查和更新地图的代码。如何做到这一点? 我知道函数
map.get(key,defaultValue)
,但我不会使用它,因为在每次迭代中创建一个实例是非常昂贵的,即使我不需要它

我想要的是一个带有闭包的get函数,用于提供默认值。在这种情况下,我将有懒惰的评估

更新
dmahapatro提供的解决方案正是我想要的。下面是一个用法示例

// simulate the result from the select
def select = [[a:1, b:2, c:3], [a:1, b:5, c:6], [a:2, b:2, c:4], [a:2, b:3, c:5]]

// a sample class for building an object hierarchie
class Master {
    int a
    List<Detail> subs = []
    String toString() { "Master(a:$a, subs:$subs)" }
}

// a sample class for building an object hierarchie
class Detail {
    int b
    int c
    String toString() { "Detail(b:$b, c:$c)" }
}

// the goal is to build  a tree from the SQL result with Master and Detail entries
// and store it in this map
def result = [:]

// iterate over the select, row is visible inside the closure
select.each { row ->
    // provide a wrapper with a default value in a closure and get the key
    // if it is not available then the closure is executed to create the object
    // and put it in the result map -> much compacter than in my question
    def theResult = result.withDefault { 
        new Master(a: row.a)
    }.get(row.a)

    // process the further columns
    theResult.subs.add new Detail(b: row.b, c: row.c )
}

// result should be [
// 1:Master(a:1, subs:[Detail(b:2, c:3), Detail(b:5, c:6)]),
// 2:Master(a:2, subs:[Detail(b:2, c:4), Detail(b:3, c:5)])]
println result
//模拟选择的结果
def select=[[a:1,b:2,c:3],[a:1,b:5,c:6],[a:2,b:2,c:4],[a:2,b:3,c:5]]
//用于构建对象层次结构的示例类
班主任{
INTA
列表子类=[]
String toString(){“Master(a:$a,subs:$subs)”}
}
//用于构建对象层次结构的示例类
课堂细节{
int b
INTC
字符串toString(){“详细信息(b:$b,c:$c)”}
}
//目标是从SQL结果构建一个包含主条目和详细条目的树
//然后把它存储在这张地图上
def结果=[:]
//在select上迭代,可以在闭包内看到行
选择.each{行->
//在闭包中提供一个带有默认值的包装器并获取密钥
//如果不可用,则执行闭包以创建对象
//把它放在结果图中->比我的问题要紧凑得多
def theResult=result.withDefault{
新母版(a:row.a)
}.get(第a行)
//处理进一步的列
theResult.subs.add新详细信息(b:row.b,c:row.c)
}
//结果应该是[
//1:船长(a:1,潜艇:[细节(b:2,c:3),细节(b:5,c:6)],
//2:船长(a:2,潜艇:[细节(b:2,c:4),细节(b:3,c:5)])
打印结果
我从这个示例中学到:

  • withDefault返回一个包装器,因此要操作映射,请使用包装器而不是原始映射
  • 行变量在闭包中可见
  • 在每次迭代中再次为映射创建包装器,因为行变量已更改

您自找的,Groovy为您准备的。:)


它的工作方式与您期望它懒惰地工作的方式相同。查看API以获得详细解释。

@ChrLipp哇,这个问题看起来与初始版本完全不同。:-)因为定义闭包时,
在范围内,所以不需要将其传递给闭包。为什么您认为
map.get(key,new Entry())
在任何情况下都会创建
新条目
?只有当键不存在时,才会获取默认值。如果它不在闭包中,则在调用函数之前,会对所有函数调用进行求值。
def map = [:]

def decoratedMap = map.withDefault{
    new Entry()
}