将地图转换为所需的地图

时间:2016-09-03 12:47:34

标签: arraylist groovy hashmap flatten

我的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

有人可以提出更好的方法来实现这个目标吗?

3 个答案:

答案 0 :(得分:2)

考虑将公共代码提取到新方法中。

(编辑:我还使用了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)

这比原版更清晰,便于单元测试。

答案 1 :(得分:1)

因为你的输入是在地图而不是一个漂亮的单位列表中,我建议的最佳计划是按照以下方式创建dataListcollect而不是附加[{{1}进入它)

<<

我可能还建议您使用 def dataList = map*.key.collect { app -> [(app) : map.findResults { it.value.findResults { (it[0] == app) ? it[2] : 0 } }.flatten()] } 并将collectEntries改为地图。

答案 2 :(得分:1)

这就是我得到的:

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 )