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) }
}
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

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'] ]
      
  • alternatives

    [ a:1, b:2, c:2 ].groupBy{ it.value }
                     .collectEntries{ k, v -> [ (k): v.collect{ it.key } ] }
    
    • result:
      [ 1:['a'], 2:['b', 'c'] ]
      

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:

try online

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'   )
    
    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 Closure

    Closure 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

try online

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

    try online

    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>> to Map<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' ]
      
  • merge two List<String> to single Map<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']
      ]
      

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

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
      

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'
Copyright © marslo 2020-2023 all right reserved,powered by GitbookLast Modified: 2024-05-16 01:41:37

results matching ""

    No results matching ""