- filter
- merge two maps
- map withDefault
- get key or value from nested Map
- findResult & findResults
- inject
- collect & collectMany
- grep
- with
- sort
- traverse
- subMap
- transpose
- convert
filter
filter via condition
[ 'a': 1, 'b': 2, 'c': 3 ].findAll{ it.value > 1 }.collectEntries { [ it.key, 4 ] }
===> [b:4, c:4]
find a string
in a nested Map
by using recursive function
def hasValue( Map m, String value ) {
m.containsValue(value) || m.values().find { v -> v instanceof Map && hasValue(v, value) }
}
- another version
inspired by stackoverflow: How to search value by key from Map as well as Nested Map
def hasValue( Map m, String value ) {
if ( m.containsValue(value) ) return m.containsValue(value)
m.findResult { k, v -> v instanceof Map ? hasValue(v, value) : null }
}
find a string
exists in a list
of Map
def isTargetExists( Map m, String subKey, String value ) {
def map = m.findAll { it.value instanceof Map }.collect { it.key }
return m.subMap(map).any { k, v -> v.get(subKey, []).contains(value) }
}
Map<String, Map<String, String>> matrix = [
dev : [
user : ['dev1', 'dev2', 'dev3'] ,
passwd : '123456',
customer : ['yahoo', 'bing']
] ,
staging : [
user : ['stg1', 'stg2', 'stg3'] ,
passwd : 'abcdefg' ,
customer : ['google', 'huawei']
] ,
prod : [
user : ['prod1', 'prod2', 'prod3'] ,
passwd : 'a1b2c3d4'
]
]
assert isTargetExists( matrix, 'user', 'dev4' ) == false
assert isTargetExists( matrix, 'customer', 'huawei' ) == true
merge two maps
for <String, List<String>>
Closure merger = { Map newMap, Map currentMap ->
currentMap.inject(newMap.clone()) { merged, entry ->
merged[entry.key] = merged.getOrDefault( entry.key, [] ) + entry.value
merged
}
}
for <String, Map<String, List<String>>>
def m1 = [ k1: [ l1: ['s1', 's2']]]
def m2 = [ k1: [ l1: ['s3', 's4']], k2: [ l2: ['x1', 'x2']] ]
def accumulator = [:].withDefault{ [:].withDefault{ [] } }
Closure merger
merger = { Map trg, Map m ->
m.each{ k, v ->
switch( v instanceof java.util.LinkedHashMap ){
case true : merger trg[ k ], v ; break ;
case false : trg[ k ].addAll v ; break ;
}
}
}
[ m1, m2 ].each merger.curry( accumulator )
assert accumulator == [k1:[l1:['s1', 's2', 's3', 's4']], k2:[l2:['x1', 'x2']]]
merge and sum
preconditions:
Map<String, Integer> m1 = [ a : 10, b : 2, c : 3 ] Map<String, Integer> m2 = [ b : 3, c : 2, d : 5 ] List<Map<String, Integer>> maps = [ m1, m2 ]
merge values into list
maps.sum { it.keySet() }.collectEntries { key -> [key, maps.findResults { it[key] } ] } // result // [a:[10], b:[2, 3], c:[3, 2], d:[5]]
sum lists
def process( List maps ) { maps.sum { it.keySet() }.collectEntries { key -> [ key, maps.findResults { it[key] }.sum() ] } }
or more elegant way via
Clousre
:> ```groovy > Closure getSum = { x -> x.sum() } > getSum( [1,2,3,4] ) == 10 > ```
def process( List maps ) { Closure getSum = { x -> x.sum() } maps.sum { it.keySet() }.collectEntries { key -> [ key, getSum(maps.findResults { it[key] }) ] } }
which can be extended to:
def process( List maps, Closure closure ) { maps.sum { it.keySet() }.collectEntries { key -> [ key, closure(maps.findResults { it[key] }) ] } } // merge maps and get sum process(maps){ x -> x.sum() } // [a:10, b:5, c:5, d:5] // merge maps and get product process(maps){ x -> x.inject(1) { sum, n -> sum * n } // [a:10, b:6, c:6, d:5] // merge maps and get the biggest item process(maps){ x -> x.inject(x[0]) { biggest, n -> biggest > n ? biggest : n } } // [a:10, b:3, c:3, d:5]
map withDefault
objective:
[a:1,b:2,c:2] ⇣⇣ [1:['a'], 2:['b','c']]
- * iMarslo: groupBy
def newMap = [:].withDefault { [] }
[ a:1, b:2, c:2 ].each { key, val ->
newMap[val] << key
}
assert newMap == [1:['a'], 2:['b','c']]
alternative
[ a:1, b:2, c:2 ].inject([:].withDefault{[]}) { map, k, v -> map[v] << k map }
- result:
[ 1:['a'], 2:['b', 'c'] ]
- result:
alternatives
[ a:1, b:2, c:2 ].groupBy{ it.value } .collectEntries{ k, v -> [ (k): v.collect{ it.key } ] }
- result:
[ 1:['a'], 2:['b', 'c'] ]
- result:
merge maps
Map map1 = [x: 1, y: 2]
Map map2 = [z: 3]
Map merged = map1.withDefault(map2.&get)
assert map1 == merged // quit interesting
assert 3 == merged.get('z')
- result
[ 'x':1, 'y':2 ]
get key or value from nested Map
insprired from :
objective:
Map<String, Map<String, String>> map = [ k1 : [ k11 : 'v11' ] , k2 : [ k11 : 'v21' ] , k3 : [ k11 : 'v31' ] ] ⇣⇣ findKeyBelongsTo( 'k11' ) » 'k1' findValueBelongsTo( 'v31' ) » 'k3'
find parent key via sub-key:
def findKeyBelongsTo( Map map, String keyword ) {
map.find { keyword in it.value.keySet() }?.key
}
- find in nested map recursively :
def findKeyBelongsTo( Map map, String keyword ) { map.findResult { k, v -> v instanceof Map ? v.containsKey(keyword) ? k : findKeyBelongsTo( v, keyword ) : null } }
find value belongs to which key
find parent key via sub-value: try online
def findValueBelongsTo( Map map, String keyword ) {
map.find { keyword in it.value.values() }?.key
}
find in nested map recursively (according to value):
def findValueBelongsTo( Map map, String keyword ) { map.findResult { k, v -> v instanceof Map ? v.containsValue(keyword) ? k : findValueBelongsTo( v, keyword ) : null } }
find in mixed map & list object recursively :
[!TIP]
Map<String, String> LOGGER = [ info : [ 'info', 'i' ], warnning : [ 'warning' , 'warn', [ 'key' : 'value' ] , 'w' ] , error : [ 'error', 'err', 'e'] ] ⇣⇣ assert 'info' == findValueBelongsTo( LOGGER , 'i' ) assert 'warning' == findValueBelongsTo( LOGGER , 'value' ) assert 'error' == findValueBelongsTo( LOGGER , 'err' )
- find in mixed map & list: try online
def findValueBelongsTo = { Map map, String keyword -> map.find { k, v -> v instanceof Map ? v.containsKey( keyword ) ? k : findValueBelongsTo(v, keyword) : v.contains( keyword ) ?: v.any{ it instanceof Map } ? findValueBelongsTo( v.findAll{ it instanceof Map }.inject([:]) { i, m -> m << i; m }, keyword) : [:] }?.key ?: null }
find in mixed map & list object recursively with Closure:
[!TIP]
call()
will be abnormal in recursive calls in ClosureClosure findValueBelongsTo findValueBelongsTo = { Map map, String keyword -> map.find { k, v -> v instanceof Map ? v.containsKey( keyword ) ? k : findValueBelongsTo( v, keyword ) : v.contains( keyword ) ?: v.any{ it instanceof Map } ? findValueBelongsTo( v.findAll{ it instanceof Map }.inject([:]) { i, m -> m << i; m }, keyword) : [:] }?.key ?: null }
findResult & findResults
- collect: return all result (with null)
groovy:000> [a: 1, b: 2, c: 3, d: 4].collect{ k, v -> v>2 ? (k + '->' + v) : null } ===> [null, null, c->3, d->4]
findResult: return the first eligible value (first non-null element)
groovy:000> [a: 1, b: 2, c: 3, d: 4].findResult{ k, v -> v>2 ? (k + '->' + v) : null } ===> c->3
findResults: find all eligible values (all non-null elements)
groovy:000> [a: 1, b: 2, c: 3, d: 4].findResults{ k, v -> v>2 ? (k + '->' + v) : null } ===> [c->3, d->4]
find deep in nested map
- example map structure:
Map map = [ 'a': [ 'b': [ 'c': [ 'd' : '1', 'e' : '2', 'f' : '3' ], 'g': '4', 'h': [ 'i': '5', 'j': '6', 'k': '7' ] ], 'l': [ 'm': '8', 'n': '9' ], 'o': '10' ] ]
find value via key name recursively
def findValues( Map map, String keyword ) { map.findResult { k, v -> v instanceof Map ? v.containsKey(keyword) ? v.getOrDefault(keyword, null) : findValues( v, keyword ) : null } }
alternatives
def findValues( Map map, String keyword ) { if( map.containsKey(keyword) ) return map.getOrDefault( keyword, null ) map.findResult { k, v -> v instanceof Map ? findValues(v, keyword) : null } }
result
println "~~> findValues( map, 'f' ) : ${findValues( map, 'f' )} " println "~~> findValues( map, 'o' ) : ${findValues( map, 'o' )} " println "~~> findValues( map, 'aaaa' ) : ${findValues( map, 'aaaa' )} " /** * console output * ~~> findValues( m, 'f' ) : 3 * ~~> findValues( m, 'o' ) : 10 * ~~> findValues( m, 'aaaa' ) : null **/
alternatives
def hasValues(Map m, String key) { m.containsKey(key) || m.find { k, v -> v instanceof Map && hasValues(v, key) } }
result
println "~~> hasValues( map, 'f' ) : ${hasValues( map, 'f' )} " println "~~> hasValues( map, 'o' ) : ${hasValues( map, 'o' )} " println "~~> hasValues( map, 'aaaa' ) : ${hasValues( map, 'aaaa' )} " /** * console output * ~~> hasValues( m, 'f' ) : true * ~~> hasValues( m, 'o' ) : true * ~~> hasValues( m, 'aaaa' ) : false **/
inject
- Join Elements to a String
def map = [q: 'groovy', maxResult: 10, start: 0, format: 'xml'] def params = map.inject([]) { result, entry -> result << "${entry.key}=${URLEncoder.encode(entry.value.toString())}" }.join('&') assert 'q=groovy&maxResult=10&start=0&format=xml' == params
collect & collectMany
collectEntries
List<Map<String, String>>
toMap<String, String>
[!NOTE|label:references:]
[ [ name:'John' , age:35 ] , [ name:'Jim' , age:54 ] , [ name:'Smith' , age:'53' ] ].collectEntries {[ it.name, it.age ]} // result: [ 'John':35, 'Jim':54, 'Smith':'53' ] // AND [ ['hi': 1], ['hello': 2], ['bello': 3] ].collectEntries() // or [ ['hi': 1], ['hello': 2], ['bello': 3] ].sum() // result: ['hi':1, 'hello':2, 'bello':3]
merge two
List<String>
to singleMap<String, List<String>>
List<String> value =['a','b','c' ] List<String> recId =['R1','R2' ] Map<String, List<String>> map = recId.collectEntries{[ it, value ]} // or Map<String, List<String>> map = recId.collectEntries{[ it, value.clone() ]}
- result
[ 'R1':['a', 'b', 'c'] , 'R2':['a', 'b', 'c'] ]
- result
collect
similar feature for
to_entries[]
in jq[!NOTE|label:
to_entries[]
in jq]$ echo '{ "a" : "1" }' | jq -r 'to_entries[]' { "key": "a", "value": "1" }
[ 'a' : '1', 'b' : '2', 'c' : '3' ].collect {[ 'key' : it.key , 'value' : it.value ]}
- result
[ [ 'key':'a', 'value':'1' ] , [ 'key':'b', 'value':'2' ] , [ 'key':'c', 'value':'3' ] ]
- result
grep
references:
['test', 12, 20, true].grep(String)
alternatives
['test', 12, 20, true].findAll { it.class.simpleName == 'String' } // or ['test', 12, 20, true].findAll { it instanceof String }
with
[!NOTE|label:references:]
Map map = [a: 1, b:2]
map.with {
(a, b) = [3, 4]
}
assert map.a == 3
assert map.b == 4
sort
descending
assert ['h3':'bb', 'h2':'cc', 'h1':'aa'] == [ 'h1' : 'aa', 'h3' : 'bb', 'h2' : 'cc' ].sort{ - it.key.split('h').last().toInteger() } # or assert ['h3':'bb', 'h2':'cc', 'h1':'aa'] == [ 'h1' : 'aa', 'h3' : 'bb', 'h2' : 'cc' ].sort{ it.key }.reversed()
traverse
references:
iterateMap && recursion
def iterateMap(Map map, String prefix = "") { map.each { key, value -> if (value instanceof Map) { iterateMap(value, "$prefix$key:") } else { println "a:$prefix$key=$value" } } } def a = [ b: [ c: 1, d: 2, e: 3 ], r: [ p: 4 ], q: 5 ] iterateMap(a)
- results:
a:b:c=1 a:b:d=2 a:b:e=3 a:r:p=4 a:q=5
- results:
subMap
[!NOTE|label:references:]
Map m = [ one: 1, two: 2, three: 3, four: 4 ]
assert [ two: 2, three: 3 ] == m.subMap(['two', 'three'])
// with groovy flexible syntax
assert [ two: 2, three: 3 ] == m.subMap('two', 'three')
// or even simple syntax
m.subMap 'two', 'three', 'non-existent'
change Map in condition
[ 'a': 1, 'b': 2, 'c': 3 ].collectEntries { ( it.value > 1 ) ? [ "${it.key}" : 4 ] : it }
===> [a:1, b:4, c:4]
- or
[ it.key, 4 ]
[ 'a': 1, 'b': 2, 'c': 3 ].collectEntries { ( it.value > 1 ) ? [ it.key, 4 ] : it }
- or
[ (it.key) : 4 ]
[ 'a': 1, 'b': 2, 'c': 3 ].collectEntries { ( it.value > 1 ) ? [ (it.key) : 4 ] : it }
check if subMap belongs to the Map
[!NOTE|label:references:]
Map map = [
'1': [ a: '1', b: '2' ],
'2': [ a: '2', b: '3' ],
'3': [ a: '3', b: '4' ]
]
Map pattern = [ a: '2' ]
map.findAll {
it.value.subMap(pattern.keySet()).any{ v -> pattern.equals([ (v.key): v.value ]) }
}
// Result: ['2':['a':'2', 'b':'3']]
map.findAll {
pattern.any { p ->
it.value.any { v -> p.key == v.key && p.value == v.value }
}
}
// Result: ['2':['a':'2', 'b':'3']]
map.findAll {
it.value.entrySet().containsAll( pattern.entrySet() )
}
// Result: ['2':['a':'2', 'b':'3']]
transpose
[!NOTE|label:references:]
Groovy Map of Lists into List of Maps
[ ╮ [ a: [ "c", "d" ], ├ [ a: "c", b: "e" ], b: [ "e", "f" ] ├ [ a: "d", b: "f" ] ] ╯ ]
assume:
Map x = [ a: [ "c","d" ], b: [ "e","f" ] ]
jenkins solution
[ x.keySet() as List, x.values() as List ].transpose() // [['a', ['c', 'd']], ['b', ['e', 'f']]] .collect { it.combinations() } // [[['a', 'c'], ['a', 'd']], [['b', 'e'], ['b', 'f']]] .transpose() // [[['a', 'c'], ['b', 'e']], [['a', 'd'], ['b', 'f']]] .collect { it.flatten() } // [['a', 'c', 'b', 'e'], ['a', 'd', 'b', 'f']] .collect { it.toSpreadMap() } // [['a':'c', 'b':'e'], ['a':'d', 'b':'f']]
groovy solution
[ x*.key, x*.value ].transpose()*.combinations().transpose()*.flatten()*.toSpreadMap() // ∙ ∙ ∙ ∙ ∙ // │ │ │ │ └─> // [['a':'c', 'b':'e'], ['a':'d', 'b':'f']] // │ │ │ └─> // [['a', 'c', 'b', 'e'], ['a', 'd', 'b', 'f']] // │ │ └─> // [[['a', 'c'], ['b', 'e']], [['a', 'd'], ['b', 'f']]] // │ └─> // [[['a', 'c'], ['a', 'd']], [['b', 'e'], ['b', 'f']]] // └─> // [['a', ['c', 'd']], ['b', ['e', 'f']]]
convert
[!NOTE|label:references:]
convert Json to Map
Map map = new groovy.json.JsonSlurper().parseText '''
{ "simple": 123,
"fraction": 123.66,
"exponential": 123e12
}'''
assert map == ['simple':123, 'fraction':123.66, 'exponential':1.23E+14]
convert Map to String
map.inspect()
Map map = [ 'a':1, 'b': 'test' ] assert map.inspect() == "['a':1, 'b':'test']"
groovy.json.JsonBuilder(map)
Map map = [ 'a':1, 'b': 'test' ] assert new groovy.json.JsonBuilder(map) .toString() .replace('{', '[') .replace('}', ']') == '["a":1,"b":"test"]'