快捷方式创build从Groovy列表中的地图?

我想要一些这样的手段:

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

鉴于GDK的东西,我希望能够做到这样的事情:

 Map rowToMap(row) { row.columns.collectMap{ [it.name,it.val] } } 

但我还没有看到任何文件…我错过了什么? 还是我太懒惰?

我最近遇到了需要做到这一点:将列表转换为地图。 这个问题在Groovy版本1.7.9发布之前发布,所以collectEntries方法还不存在。 它和提出的collectMap方法完全一样:

 Map rowToMap(row) { row.columns.collectEntries{[it.name, it.val]} } 

如果出于某种原因,您仍旧使用旧的Groovy版本,则也可以使用inject方法(如此处所述 )。 这是一个稍微修改过的版本,只在闭包内部使用一个expression式(只是为了保存字符):

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

也可以使用+运算符来代替<<

检查“注入”。 真正的函数式编程的人称它为“折叠”。

 columns.inject([:]) { memo, entry -> memo[entry.name] = entry.val return memo } 

而且,当你在这个时候,你可能想把方法定义为类而不是在metaClass上。 这样,您可以为所有Collections定义一次:

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

用法示例:

 use(PropertyMapCategory) { println columns.mapProperty('name', 'val') } 

当这个问题被问到时, groupBy方法是否不可用?

另外,如果您使用的是Googlecollections集( http://code.google.com/p/google-collections/ ),则可以这样做:

  map = Maps.uniqueIndex(list, Functions.identity()); 

好的…我已经玩了一点,我觉得这是一个非常酷的方法…

 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 

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

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

 [1:2, 3:4].collectMap{[it.value, it.key]} == [2:1, 4:3] 

在这里我用它来创build一个列表中的地图

 [1,2].collectMap{[it,it]} == [1:1, 2:2] 

现在我只是popup这个到一个类被调用,因为我的应用程序正在启动,这个方法在我的代码中可用。

编辑:

将该方法添加到所有数组…

 Object[].metaClass.collectMap = collectMap 

我找不到内置的东西…但使用ExpandoMetaClass我可以这样做:

 ArrayList.metaClass.collectMap = {Closure callback-> def map = [:] delegate.each { def r = callback.call(it) map[r[0]] = r[1] } return map } 

这将collectMap方法添加到所有ArrayList …我不知道为什么将它添加到List或Collection不起作用..我想这是另一个问题…但现在我可以做到这一点…

 assert ["foo":"oof", "42":"24", "bar":"rab"] == ["foo", "42", "bar"].collectMap { return [it, it.reverse()] } 

从列表计算一个闭包地图…正是我在找什么。

编辑:我无法将该方法添加到接口List和Collection的原因是因为我没有这样做:

 List.metaClass.enableGlobally() 

在那个方法调用之后,你可以添加方法到接口..在这种情况下,这意味着我的collectMap方法可以在这样的范围内工作:

 (0..2).collectMap{[it, it*2]} 

这将产生地图:[0:0,1:2,2:4]

这样的事情呢?

 // setup class Pair { String k; String v; public Pair(def k, def v) { this.k = k ; this.v = v; } } def list = [ new Pair('a', 'b'), new Pair('c', 'd') ] // the idea def map = [:] list.each{ it -> map.putAt(it.k, it.v) } // verify println map['c'] 

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

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

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

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