在groovy中从列表创建Map的快捷方式?

dan*_*anb 102 java collections groovy expandometaclass

我想对此进行一些分类:

Map rowToMap(row) {
    def rowMap = [:];
    row.columns.each{ rowMap[it.name] = it.val }
    return rowMap;
}
Run Code Online (Sandbox Code Playgroud)

考虑到GDK的方式,我希望能够做到这样的事情:

Map rowToMap(row) {
    row.columns.collectMap{ [it.name,it.val] }
}
Run Code Online (Sandbox Code Playgroud)

但是我没有在文档中看到任何内容......我错过了什么吗?还是我太懒了?

epi*_*ian 112

我最近遇到了这样做的需要:将列表转换为地图.这个问题是在Groovy 1.7.9版本发布之前发布的,所以该方法collectEntries尚不存在.它的工作原理与建议collectMap方法完全相同:

Map rowToMap(row) {
    row.columns.collectEntries{[it.name, it.val]}
}
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因你坚持使用旧的Groovy版本,该inject方法也可以用(如建议在这里).这是一个稍微修改过的版本,在闭包内只占用一个表达式(只是为了保存字符!):

Map rowToMap(row) {
    row.columns.inject([:]) {map, col -> map << [(col.name): col.val]}
}
Run Code Online (Sandbox Code Playgroud)

+运营商还可以用来代替<<.


Rob*_*her 28

看看"注入".真正的函数式编程让人称之为"折叠".

columns.inject([:]) { memo, entry ->
    memo[entry.name] = entry.val
    return memo
}
Run Code Online (Sandbox Code Playgroud)

而且,当你在它的时候,你可能想要在metaClass上将方法定义为Categories而不是right.这样,您可以为所有集合定义一次:

class PropertyMapCategory {
    static Map mapProperty(Collection c, String keyParam, String valParam) {
        return c.inject([:]) { memo, entry ->
            memo[entry[keyParam]] = entry[valParam]
            return memo
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

use(PropertyMapCategory) {
    println columns.mapProperty('name', 'val')
}
Run Code Online (Sandbox Code Playgroud)


Ami*_*far 13

当问到这个问题时,groupBy方法不可用吗?


ogr*_*nek 5

此外,如果您使用谷歌收藏集(http://code.google.com/p/google-collections/),您可以执行以下操作:

  map = Maps.uniqueIndex(list, Functions.identity());
Run Code Online (Sandbox Code Playgroud)


dan*_*anb 5

好的...我已经玩过这个了,我认为这是一个非常酷的方法......

def collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}
ExpandoMetaClass.enableGlobally()
Collection.metaClass.collectMap = collectMap
Map.metaClass.collectMap = collectMap
Run Code Online (Sandbox Code Playgroud)

现在Map或Collection的任何子类都有这个方法......

在这里我用它来反转Map中的键/值

[1:2, 3:4].collectMap{[it.value, it.key]} == [2:1, 4:3]
Run Code Online (Sandbox Code Playgroud)

在这里我用它从列表中创建一个地图

[1,2].collectMap{[it,it]} == [1:1, 2:2]
Run Code Online (Sandbox Code Playgroud)

现在我只是把它弹出到一个类中,当我的应用程序启动时调用它,这个方法在我的代码中都可用.

编辑:

将方法添加到所有数组...

Object[].metaClass.collectMap = collectMap
Run Code Online (Sandbox Code Playgroud)


Ner*_*rve 5

如果您需要的是一个简单的键值对,那么该方法collectEntries就足够了.例如

def names = ['Foo', 'Bar']
def firstAlphabetVsName = names.collectEntries {[it.charAt(0), it]} // [F:Foo, B:Bar]
Run Code Online (Sandbox Code Playgroud)

但是如果你想要一个类似于Multimap的结构,其中每个键有多个值,那么你想要使用该groupBy方法

def names = ['Foo', 'Bar', 'Fooey']
def firstAlphabetVsNames = names.groupBy { it.charAt(0) } // [F:[Foo, Fooey], B:[Bar]]
Run Code Online (Sandbox Code Playgroud)