2016-09-03 2 views
1

У меня есть 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.

Может ли кто-нибудь предложить лучший способ достичь этого?

ответ

2

Рассмотрим извлекая общий код в новый метод.

(Edit: Я также использовал collect и collectEntries для очистки секции 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

' collect' все еще можно использовать здесь, чтобы удалить создание и добавление к 'tempMap' – RudolphEst

+1

Да ваше решение выглядит намного чище ... :) –

+2

Я очистил раздел' dataList' за каждое предложение ... Мне потребовалось некоторое время, чтобы увидеть двойную итерацию (то есть список карт). –

1

Поскольку ваш вход в карту вместо красивого плоского списка, лучший план до Я могу порекомендовать создать dataList следующим образом (collect в него вместо добавления [<<] в него)

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

Я бы также рекомендовал использовать collectEntries и сделать вместо этого dataList карту.

+0

Спасибо за ваши предложения ... :) –

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) 
+0

Это впечатляющее решение, но разве это не слишком сложно? Что случилось с тем, как первоначально был создан 'moduleList'? Однако Kudo на «уникальном», я не думал о повторных именах модулей. – RudolphEst

+1

это так сложно, как это требует бизнес-логика. – injecteer

+1

Я вежливо не согласен, бизнес-логика имеет очень мало общего с выбором использования функций, предоставляемых API (таких как 'addAll' и' collect', 'findResults') вместо создания программы только с помощью' inject 'сокращение. Я думаю, что оригинальное решение OP было более простым, понятным и более удобным. – RudolphEst

Смежные вопросы