【问题标题】:Map with default value created in a closure具有在闭包中创建的默认值的映射
【发布时间】:2013-06-29 01:12:39
【问题描述】:

我想将对象存储在地图中(称为结果)。对象是从 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

我从这个示例中学到了什么:

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

【问题讨论】:

  • 由于row在定义闭包时在作用域内,所以不需要将其传递给闭包。
  • 为什么你认为map.get(key, new Entry()) 在任何情况下都会创建new Entry?仅当键不存在时才获取默认值。
  • 如果它不在闭包中,所有函数调用都会在函数被调用之前进行评估。

标签: groovy


【解决方案1】:

您需要它,Groovy 已经为您准备好了。 :)

def map = [:]

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

它的工作方式与您期望它懒惰地工作的方式相同。详细解释请看withDefault API。

【讨论】:

  • @ChrLipp 哇,这个问题看起来与最初的版本完全不同。 :-)
猜你喜欢
  • 2015-01-13
  • 1970-01-01
  • 2018-01-03
  • 2012-11-28
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
相关资源
最近更新 更多