элегантный способ объединить карту структура с использованием groovy - PullRequest
0 голосов
/ 19 июня 2020

У меня есть структура вложенной карты:

Map<String, List<String>> case_pool = [
  dev : [
    funcA : ['devCaseA'] ,
    funcB : ['devCaseB'] ,
    funcC : ['devCaseC']
  ],
  'dev/funcA' : [
    funcA : ['performanceCaseA']
  ],
  'dev/funcA/feature' : [
    funcA : ['performanceCaseA', 'featureCase']
  ],
  staging : [
   funcB : ['stgCaseB'] ,
   funcC : ['stgCaseC']
  ]
]

и я хочу получить результат, когда branch.contains(case_pool.key), затем объедините список случаев. т.е.:

String branch = 'dev/funcA/feature-1.0'

// will final get result of " 'dev' + 'dev/funcA' + 'dev/funcA/feature' ":
result: 
[
  funcA: [ "devCaseA", "performanceCaseA", "featureCase" ],
  funcB: [ "devCaseB" ],
  funcC: [ "devCaseC" ]
]

Сначала я использую l oop:

String branch = 'dev/funcA/feature-1.0'
def result = [:].withDefault { [] as Set }
case_pool.keySet().each {
  if ( branch.contains(it) ) {
    case_pool.get(it).each { k, v ->
      result[k].addAll(v)
    }
  }
}
println 'result: ' + result

Во-вторых, я использую закрытие:


String branch = 'dev/funcA/feature-1.0'
def result = [:].withDefault { [] as Set }
case_pool.findAll{ k, v -> branch.contains(k) }.collectMany{ k, v -> v.collect{ c, l ->
    result[c].addAll(l)
}}
println 'result: ' + result

Однако , Мне не нравится путь .collectMany{ k, v -> v.collect{ c, l -> }}. Есть ли лучшие решения? (например: используя groupBy или что-то в этом роде)

Кстати, я пробовал collectEntries, и оказалось, что окончательный список заменит все:

String branch = 'dev/funcA/feature-1.0'
println case_pool.findAll{ k, v -> branch.contains(k) }.collect{ k, v -> v}.collectEntries{it}

result: [funcA:[performanceCaseA, featureCase], funcB:[devCaseB], funcC:[devCaseC]]

последний funcA : ['performanceCaseA', 'featureCase'] заменил все funcA: []

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Как говорит cfrick, здесь лучше inject, ie:

def result = case_pool.inject([:].withDefault { [] as Set }) { result, key, value ->
    if (branch.contains(key)) {
        value.each { k, v ->
            result[k] += v
        }
    }
    result
}
0 голосов
/ 21 июля 2020

, чтобы избежать проблемы java.io.NotSerializableException: groovy.lang.MapWithDefault в Jenkins и даже не удалось с использованием @ NonCPS .

Вот парные решения:

  1. продолжайте использовать inject([:].withDefault{}) который опубликовал @tim_yates, просто переназначьте groovy.lang.MapWithDefault на java.util.LinkedHashMap:
    Map<String, List<String>> result = [:]
    case_pool.inject([:].withDefault { [] as Set }) { res, key, value ->
      if (branch.contains(key)) {
        value.each { k, v -> res[k] += v }
      }; result
    }.collect { k, v -> result[k] = v }
    
  2. используя [].flatten().unique():
    Map<String, List<String>> result = [:]
    case_pool.collect { key, value ->
      if (branch.contains(key)) {    
        value.collect { k, v -> 
          result[k] = [result.getOrDefault(k,[]), v].flatten().unique()
        }
      }
    }
    
  3. используя findAll{} + collect{}:
    Map<String, List<String>> result = [:]
    case_pool.findAll{ k, v -> branch.contains(k) }.collect{ k, v -> 
      v.keySet().each {
        result[it] = (result.getOrDefault(it,[]) + v[it]).flatten().unique()
      }
    }
    
...