Domanda

Vorrei una mano per questo:

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

visto come sono le cose di GDK, mi aspetterei di essere in grado di fare qualcosa del tipo:

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

ma non ho visto nulla nei documenti...mi sto perdendo qualcosa?o sono semplicemente troppo pigro?

È stato utile?

Soluzione

Recentemente mi sono imbattuto nella necessità di fare esattamente questo:convertire un elenco in una mappa.Questa domanda è stata pubblicata prima che uscisse la versione 1.7.9 di Groovy, quindi il metodo collectEntries non esisteva ancora.Funziona esattamente come collectMap metodo quello è stato proposto:

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

Se per qualche motivo sei bloccato con una versione precedente di Groovy, il file inject può essere utilizzato anche il metodo (come proposto Qui).Questa è una versione leggermente modificata che accetta solo un'espressione all'interno della chiusura (solo per salvare il carattere!):

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

IL + è anche possibile utilizzare l'operatore al posto dell' <<.

Altri suggerimenti

Controlla "iniettare".I veri esperti di programmazione funzionale lo chiamano "fold".

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

E, già che ci sei, probabilmente vorrai definire i metodi come Categorie invece che direttamente sulla metaClasse.In questo modo, puoi definirlo una volta per tutte le raccolte:

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

Utilizzo di esempio:

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

Era la raggruppa per metodo non disponibile quando è stata posta questa domanda?

Inoltre, se utilizzi le raccolte Google (http://code.google.com/p/google-collections/), puoi fare qualcosa del genere:

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

OK...Ci ho giocato un po' di più e penso che sia un metodo piuttosto interessante...

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

ora qualsiasi sottoclasse di Map o Collection ha questo metodo...

qui lo uso per invertire la chiave/valore in una mappa

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

e qui lo uso per creare una mappa da un elenco

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

ora lo inserisco semplicemente in una classe che viene chiamata all'avvio della mia app e questo metodo è disponibile in tutto il mio codice.

MODIFICARE:

per aggiungere il metodo a tutti gli array...

Object[].metaClass.collectMap = collectMap

Se ciò di cui hai bisogno è una semplice coppia chiave-valore, allora il metodo collectEntries dovrebbe bastare.Per esempio

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

Ma se vuoi una struttura simile a una Multimap, in cui ci sono più valori per chiave, allora dovresti usare il metodo groupBy metodo

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

non riesco a trovare nulla di integrato...ma usando ExpandoMetaClass posso fare questo:

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

questo aggiunge il metodo CollectMap a tutti gli ArrayList...Non sono sicuro del motivo per cui l'aggiunta all'elenco o alla raccolta non ha funzionato.Immagino che sia per un'altra domanda...ma ora posso farlo...

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

dall'elenco alla mappa calcolata con una chiusura...esattamente quello che stavo cercando.

Modificare:il motivo per cui non ho potuto aggiungere il metodo alle interfacce List e Collection era perché non l'ho fatto:

List.metaClass.enableGlobally()

dopo la chiamata al metodo, puoi aggiungere metodi alle interfacce.che in questo caso significa che il mio metodo CollectMap funzionerà su intervalli come questo:

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

che restituisce la mappa:[0:0, 1:2, 2:4]

Che ne dici di qualcosa del genere?

// 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']
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top