Groovy:将字符串转换为多图
Groovy: Transforming a String into a Multimap
所以我有一个看起来有点像这样的字符串:
text = "foo/bar;baz/qux"
我的最终目标是将这个字符串拆分成一个 Multimap,如下所示:
["level1" : ["foo", "baz"], "level2" : ["bar", "qux"]]
我还为 LinkedHashMap 的元类添加了 Multimap 支持:
LinkedHashMap.metaClass.multiPut << { key, value ->
delegate[key] = delegate[key] ?: []; delegate[key] += value
}
字符串需要在分号处拆分,然后在正斜杠处再次拆分。目前我正在嵌套的 for 循环中填充我的 Multimap,但显然有一种 Groovier 方法可以做到这一点。因此我想知道我的选择是什么?
我的想法大致如下:
def final myMap = text.split(';')
.collectEntries { it.split('/')
.eachWithIndex { entry, index -> ["level${index + 1}" : entry] }}
您可以在返回的地图上使用 withDefault
来摆脱三元:
def text = "foo/bar;baz/qux;foo/bar/woo"
def result = text.split(';')*.split('/').inject([:].withDefault {[]}) { map, value ->
value.eachWithIndex { element, idx ->
map["level${idx+1}"] << element
}
map
}
assert result == [level1:['foo', 'baz', 'foo'], level2:['bar', 'qux', 'bar'], level3:['woo']]
如果您不想在结果中出现重复,那么您可以在 withDefault 中使用一个 Set(然后再转换回一个 List):
def text = "foo/bar;baz/qux;foo/bar/woo"
def result = text.split(';')*.split('/').inject([:].withDefault {[] as Set}) { map, value ->
value.eachWithIndex { element, idx ->
map["level${idx+1}"] << element
}
map
}.collectEntries { key, value -> [key, value as List] }
assert result == [level1:['foo', 'baz'], level2:['bar', 'qux'], level3:['woo']]
我的看法,我不认为它很聪明,但我发现它更容易阅读:
def myMap = [:]
text.split(';').eachWithIndex{ entry, index ->
myMap << ["level${index + 1}": entry.split('/')]
}
如果您使用的是 Groovy 2.4.0 或更高版本,您可以使用已添加到 java.lang.Iterable
:
的 withIndex()
方法
def myMap = text.split(';').withIndex().collect{ entry, index ->
["level${index + 1}": entry.split('/')]
}
所以我有一个看起来有点像这样的字符串:
text = "foo/bar;baz/qux"
我的最终目标是将这个字符串拆分成一个 Multimap,如下所示:
["level1" : ["foo", "baz"], "level2" : ["bar", "qux"]]
我还为 LinkedHashMap 的元类添加了 Multimap 支持:
LinkedHashMap.metaClass.multiPut << { key, value ->
delegate[key] = delegate[key] ?: []; delegate[key] += value
}
字符串需要在分号处拆分,然后在正斜杠处再次拆分。目前我正在嵌套的 for 循环中填充我的 Multimap,但显然有一种 Groovier 方法可以做到这一点。因此我想知道我的选择是什么?
我的想法大致如下:
def final myMap = text.split(';')
.collectEntries { it.split('/')
.eachWithIndex { entry, index -> ["level${index + 1}" : entry] }}
您可以在返回的地图上使用 withDefault
来摆脱三元:
def text = "foo/bar;baz/qux;foo/bar/woo"
def result = text.split(';')*.split('/').inject([:].withDefault {[]}) { map, value ->
value.eachWithIndex { element, idx ->
map["level${idx+1}"] << element
}
map
}
assert result == [level1:['foo', 'baz', 'foo'], level2:['bar', 'qux', 'bar'], level3:['woo']]
如果您不想在结果中出现重复,那么您可以在 withDefault 中使用一个 Set(然后再转换回一个 List):
def text = "foo/bar;baz/qux;foo/bar/woo"
def result = text.split(';')*.split('/').inject([:].withDefault {[] as Set}) { map, value ->
value.eachWithIndex { element, idx ->
map["level${idx+1}"] << element
}
map
}.collectEntries { key, value -> [key, value as List] }
assert result == [level1:['foo', 'baz'], level2:['bar', 'qux'], level3:['woo']]
我的看法,我不认为它很聪明,但我发现它更容易阅读:
def myMap = [:]
text.split(';').eachWithIndex{ entry, index ->
myMap << ["level${index + 1}": entry.split('/')]
}
如果您使用的是 Groovy 2.4.0 或更高版本,您可以使用已添加到 java.lang.Iterable
:
withIndex()
方法
def myMap = text.split(';').withIndex().collect{ entry, index ->
["level${index + 1}": entry.split('/')]
}