将地图转换为所需的地图

Convert map into desired map

我有一个 map 结构如下:-

def map = [107:[[107, "Module 01", 1], [107, "Module New", 6]], 109:[[109, "Module 04", 1]]]

我们有一个任务来表示这个 map 如下结构:-

Application | Module 01 | Module New | Module 04
107         |    1      |     6      |   0
109         |    0      |     0      |   1

所以对于这个表示,我想过滤 map 如下:-

def outputMap = [moduleList:["Module 01", "Module New", "Module 04"], dataList:[[107:[1, 6, 0]], [109:[0, 0, 1]]]]

所以为了实现这个,我做了如下:-

def getFilteredMap(Map map) {
        def moduleList = map.findResults {
            it.value.findResults { it[1] }
        }.flatten()

        def dataList = []

        map*.key.each { app ->
            def tempMap = [:]
            tempMap[app] = map.findResults {
                it.value.findResults {
                    (it[0] == app) ? it[2] : 0
                }
            }.flatten()
            dataList << tempMap
        }

    return ["moduleList" : moduleList, "dataList" : dataList]
}

def map = [107:[[107, "Module 01", 1], [107, "Module New", 6]], 109:[[109, "Module 04", 1]]]
def outputMap = [moduleList:["Module 01", "Module New", "Module 04"], dataList:[[107:[1, 6, 0]], [109:[0, 0, 1]]]]
assert outputMap == getFilteredMap(map)

但是如您所见,getFilteredMap() 过滤地图作为期望输出的方法不是很好。

注意 :- 模块名称可能会在此处重复,但我只希望唯一的模块名称列表表示为 Set.

谁能提出更好的实现方法?

因为您的输入是在地图而不是漂亮的平面列表中,所以我可以推荐的最佳计划是创建 dataList 如下(collect 到其中而不是附加 [<<] 进去)

   def dataList =  map*.key.collect { app ->
        [(app) : map.findResults {
            it.value.findResults {
                (it[0] == app) ? it[2] : 0
            }
        }.flatten()]
    }

我可能还建议使用 collectEntries 并制作 dataList 地图。

这是我得到的:

def transformMap( map ) {
  // 1st collect all names to be used as 0-filled "grid-pattern"
  def moduleList = map.values().inject( [] ){ res, curr ->
    for( v in curr ) res << v[ 1 ]
    res
  }.unique()

// now fill the dataList, positioning the values according to the grid
  def dataList = map.inject( [:].withDefault{ [0] * moduleList.size() } ){ res, curr ->
    for( v in curr.value ) res[ curr.key ][ moduleList.indexOf( v[ 1 ] ) ] = v[ 2 ]
    res
  }.inject( [] ){ res, curr ->
    res << [( curr.key ): curr.value]
    res
  }

  [moduleList: moduleList, dataList: dataList]
}


def m = [107: [[107, "Module 01", 1], [107, "Module New", 6]], 109: [[109, "Module 04", 1]]]
def expected = [moduleList:["Module 01", "Module New", "Module 04"], dataList:[[107:[1, 6, 0]], [109:[0, 0, 1]]]]

assert expected == transformMap( m )

考虑将通用代码提取到新方法中。

(编辑:我还使用 collectcollectEntries 来清理 dataList 部分,正如 RudolphEst 所建议的那样)

def findAsFlat(map, f) {
    map.findResults { it.value.findResults(f) }.flatten()
}

def getFilteredMap(Map map) {
    def moduleList = findAsFlat(map, { it[1] })

    def dataList = map*.key.collect { app ->
        map.collectEntries ([:]) { 
            [app, findAsFlat(map, {(it[0] == app) ? it[2] : 0})]
        }
    }

    return ["moduleList" : moduleList, "dataList" : dataList]
}

def map = [107:[[107, "Module 01", 1], [107, "Module New", 6]], 109:[[109, "Module 04", 1]]]
def outputMap = [moduleList:["Module 01", "Module New", "Module 04"], dataList:[[107:[1, 6, 0]], [109:[0, 0, 1]]]]
assert outputMap == getFilteredMap(map)

这比原来的更清楚,并且有利于单元测试。