Pergunta

Eu gostaria de uma classificação para isso:

Map rowToMap(row) {
    def rowMap = [:];
    row.columns.each{ rowMap[it.name] = it.val }
    return rowMap;
}

dada a forma como o material do GDK é, espero poder fazer algo como:

Map rowToMap(row) {
    row.columns.collectMap{ [it.name,it.val] }
}

mas não vi nada nos documentos ...estou esquecendo de algo?ou sou muito preguiçoso?

Foi útil?

Solução

Recentemente, descobri a necessidade de fazer exatamente isso:convertendo uma lista em um mapa.Esta pergunta foi postada antes do lançamento da versão 1.7.9 do Groovy, então o método collectEntries ainda não existia.Funciona exatamente como o collectMap método que foi proposto:

Map rowToMap(row) {
    row.columns.collectEntries{[it.name, it.val]}
}

Se por algum motivo você estiver preso a uma versão mais antiga do Groovy, o inject método também pode ser usado (conforme proposto aqui).Esta é uma versão ligeiramente modificada que leva apenas uma expressão dentro do encerramento (apenas para salvar caracteres!):

Map rowToMap(row) {
    row.columns.inject([:]) {map, col -> map << [(col.name): col.val]}
}

O + operador também pode ser usado em vez do <<.

Outras dicas

Confira "injetar".Os verdadeiros especialistas em programação funcional chamam isso de "dobrar".

columns.inject([:]) { memo, entry ->
    memo[entry.name] = entry.val
    return memo
}

E, já que está nisso, você provavelmente deseja definir métodos como categorias em vez de diretamente na metaClasse.Dessa forma, você pode defini-lo uma vez para todas as Coleções:

class PropertyMapCategory {
    static Map mapProperty(Collection c, String keyParam, String valParam) {
        return c.inject([:]) { memo, entry ->
            memo[entry[keyParam]] = entry[valParam]
            return memo
        }
    }
}

Exemplo de uso:

use(PropertyMapCategory) {
    println columns.mapProperty('name', 'val')
}

Era o grupoBy método não estava disponível quando esta pergunta foi feita?

Além disso, se você usar coleções do Google (http://code.google.com/p/google-collections/), você pode fazer algo assim:

  map = Maps.uniqueIndex(list, Functions.identity());

OK...Já brinquei um pouco mais com isso e acho que é um método bem legal...

def collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}
ExpandoMetaClass.enableGlobally()
Collection.metaClass.collectMap = collectMap
Map.metaClass.collectMap = collectMap

agora qualquer subclasse de Map ou Collection possui este método ...

aqui eu uso para reverter a chave/valor em um mapa

[1:2, 3:4].collectMap{[it.value, it.key]} == [2:1, 4:3]

e aqui eu uso para criar um mapa a partir de uma lista

[1,2].collectMap{[it,it]} == [1:1, 2:2]

agora eu simplesmente coloco isso em uma classe que é chamada quando meu aplicativo está sendo iniciado e esse método está disponível em todo o meu código.

EDITAR:

para adicionar o método a todos os arrays ...

Object[].metaClass.collectMap = collectMap

Se o que você precisa é de um par de valores-chave simples, então o método collectEntries deveria ser suficiente.Por exemplo

def names = ['Foo', 'Bar']
def firstAlphabetVsName = names.collectEntries {[it.charAt(0), it]} // [F:Foo, B:Bar]

Mas se você quiser uma estrutura semelhante a um Multimap, na qual existem vários valores por chave, então você gostaria de usar o groupBy método

def names = ['Foo', 'Bar', 'Fooey']
def firstAlphabetVsNames = names.groupBy { it.charAt(0) } // [F:[Foo, Fooey], B:[Bar]]

Não consigo encontrar nada embutido...mas usando o ExpandoMetaClass eu posso fazer isso:

ArrayList.metaClass.collectMap = {Closure callback->
    def map = [:]
    delegate.each {
        def r = callback.call(it)
        map[r[0]] = r[1]
    }
    return map
}

isso adiciona o método collectMap a todos os ArrayLists...Não sei por que adicioná-lo à Lista ou Coleção não funcionou.Acho que isso é para outra pergunta...mas agora posso fazer isso...

assert ["foo":"oof", "42":"24", "bar":"rab"] ==
            ["foo", "42", "bar"].collectMap { return [it, it.reverse()] }

da lista para o mapa calculado com um fechamento...Exatamente o que eu estava procurando.

Editar:o motivo pelo qual não consegui adicionar o método às interfaces List e Collection foi porque não fiz isso:

List.metaClass.enableGlobally()

após essa chamada de método, você pode adicionar métodos às interfaces.o que neste caso significa que meu método collectMap funcionará em intervalos como este:

(0..2).collectMap{[it, it*2]}

que produz o mapa:[0:0, 1:2, 2:4]

Que tal algo assim?

// setup
class Pair { 
    String k; 
    String v; 
    public Pair(def k, def v) { this.k = k ; this.v = v; }
}
def list = [ new Pair('a', 'b'), new Pair('c', 'd') ]

// the idea
def map = [:]
list.each{ it -> map.putAt(it.k, it.v) }

// verify
println map['c']
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top