Java 从groovy中的列表创建地图的快捷方式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:12:48  来源:igfitidea点击:

shortcut for creating a Map from a List in groovy?

javacollectionsgroovyexpandometaclass

提问by danb

I'd like some sorthand for this:

我想为此提供一些帮助:

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

given the way the GDK stuff is, I'd expect to be able to do something like:

考虑到 GDK 的内容,我希望能够执行以下操作:

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

but I haven't seen anything in the docs... am I missing something? or am I just way too lazy?

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

采纳答案by epidemian

I've recently came across the need to do exactly that: converting a list into a map. This question was posted before Groovy version 1.7.9 came out, so the method collectEntriesdidn't exist yet. It works exactly as the collectMapmethod that was proposed:

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

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

If for some reason you are stuck with an older Groovy version, the injectmethod can also be used (as proposed here). This is a slightly modified version that takes only one expression inside the closure (just for the sake of character saving!):

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

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

The +operator can also be used instead of the <<.

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

回答by danb

I can't find anything built in... but using the ExpandoMetaClass I can do this:

我找不到任何内置的东西......但是使用 ExpandoMetaClass 我可以做到这一点:

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

this adds the collectMap method to all ArrayLists... I'm not sure why adding it to List or Collection didn't work.. I guess that's for another question... but now I can do this...

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

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

from List to calculated Map with one closure... exactly what I was looking for.

从 List 到计算 Map 和一个闭包……正是我想要的。

Edit: the reason I couldn't add the method to the interfaces List and Collection was because I did not do this:

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

List.metaClass.enableGlobally()

after that method call, you can add methods to interfaces.. which in this case means my collectMap method will work on ranges like this:

在该方法调用之后,您可以向接口添加方法.. 在这种情况下,这意味着我的 collectMap 方法将在如下范围内工作:

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

which yields the map: [0:0, 1:2, 2:4]

生成地图:[0:0, 1:2, 2:4]

回答by ogrodnek

Also, if you're use google collections (http://code.google.com/p/google-collections/), you can do something like this:

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

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

回答by danb

ok... I've played with this a little more and I think this is a pretty cool method...

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

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

now any subclass of Map or Collection have this method...

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

here I use it to reverse the key/value in a Map

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

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

and here I use it to create a map from a list

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

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

now I just pop this into a class that gets called as my app is starting and this method is available throughout my code.

现在我只是将它弹出到一个在我的应用程序启动时被调用的类中,并且这个方法在我的整个代码中都可用。

EDIT:

编辑:

to add the method to all arrays...

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

Object[].metaClass.collectMap = collectMap

回答by Michael Easter

What about something like this?

这样的事情怎么办?

// 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']

回答by Robert Fischer

Check out "inject". Real functional programming wonks call it "fold".

查看“注入”。真正的函数式编程专家称其为“折叠”。

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

And, while you're at it, you probably want to define methods as Categories instead of right on the metaClass. That way, you can define it once for all Collections:

并且,当您在使用它时,您可能希望将方法定义为类别,而不是直接定义在元类上。这样,您可以为所有集合定义一次:

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

Example usage:

用法示例:

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

回答by Amir Raminfar

Was the groupBymethod not available when this question was asked?

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

回答by Nerrve

If what you need is a simple key-value pair, then the method collectEntriesshould suffice. For example

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

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

But if you want a structure similar to a Multimap, in which there are multiple values per key, then you'd want to use the groupBymethod

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

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