- change Map in condition
- filter
- merge two maps
- map withDefault
- get key or value from nested Map
- findResult & findResults
- inject
- collect & collectMany
- grep
- with
- sort
- traverse
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 }
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'
], // c
'g': '4',
'h': [
'i': '5',
'j': '6',
'k': '7'
] // h
], // b
'l': [
'm': '8',
'n': '9'
], // l
'o': '10'
] // a
]
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' ]
- result
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: