Frage

Ich hätte gerne etwas Hilfe dafür:

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

Angesichts der Art und Weise, wie das GDK-Zeug ist, würde ich erwarten, dass ich so etwas tun kann:

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

aber ich habe nichts in den Dokumenten gesehen ...Vermisse ich etwas?oder bin ich einfach viel zu faul?

War es hilfreich?

Lösung

Ich bin kürzlich auf die Notwendigkeit gestoßen, genau das zu tun:Konvertieren einer Liste in eine Karte.Diese Frage wurde gestellt, bevor Groovy Version 1.7.9 herauskam, also die Methode collectEntries existierte noch nicht.Es funktioniert genau so collectMap Methode das wurde vorgeschlagen:

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

Wenn Sie aus irgendeinem Grund bei einer älteren Groovy-Version nicht weiterkommen, ist die inject Methode kann ebenfalls verwendet werden (wie vorgeschlagen). Hier).Dies ist eine leicht modifizierte Version, die nur einen Ausdruck innerhalb des Abschlusses benötigt (nur aus Gründen der Zeichenersparnis!):

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

Der + Der Operator kann auch anstelle von verwendet werden <<.

Andere Tipps

Schauen Sie sich „injizieren“ an.Echte funktionale Programmierer nennen es „Falten“.

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

Und wenn Sie schon dabei sind, möchten Sie wahrscheinlich Methoden als Kategorien definieren, anstatt direkt in der metaClass.Auf diese Weise können Sie es einmal für alle Sammlungen definieren:

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

Beispielverwendung:

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

War das gruppiere nach Methode nicht verfügbar, als diese Frage gestellt wurde?

Auch wenn Sie Google-Sammlungen verwenden (http://code.google.com/p/google-collections/), können Sie so etwas tun:

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

OK...Ich habe ein bisschen mehr damit gespielt und finde, dass das eine ziemlich coole Methode ist ...

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

Jetzt hat jede Unterklasse von Map oder Collection diese Methode ...

Hier verwende ich es, um den Schlüssel/Wert in einer Map umzukehren

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

und hier verwende ich es, um eine Karte aus einer Liste zu erstellen

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

Jetzt füge ich dies einfach in eine Klasse ein, die aufgerufen wird, wenn meine App gestartet wird, und diese Methode ist in meinem gesamten Code verfügbar.

BEARBEITEN:

um die Methode allen Arrays hinzuzufügen ...

Object[].metaClass.collectMap = collectMap

Wenn Sie ein einfaches Schlüssel-Wert-Paar benötigen, dann die Methode collectEntries sollte reichen.Zum Beispiel

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

Wenn Sie jedoch eine Struktur ähnlich einer Multimap wünschen, bei der es mehrere Werte pro Schlüssel gibt, sollten Sie die verwenden groupBy Methode

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

Ich kann nichts eingebautes finden...aber mit der ExpandoMetaClass kann ich Folgendes tun:

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

Dadurch wird die CollectMap-Methode zu allen ArrayLists hinzugefügt ...Ich bin mir nicht sicher, warum das Hinzufügen zur Liste oder Sammlung nicht funktioniert hat.Ich schätze, das ist eine andere Frage...aber jetzt kann ich das machen...

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

von der Liste zur berechneten Karte mit einem Abschluss ...genau das, was ich gesucht habe.

Bearbeiten:Der Grund, warum ich die Methode nicht zur Schnittstellenliste und -sammlung hinzufügen konnte, war, dass ich Folgendes nicht getan habe:

List.metaClass.enableGlobally()

Nach diesem Methodenaufruf können Sie Methoden zu Schnittstellen hinzufügen.was in diesem Fall bedeutet, dass meine CollectMap-Methode für Bereiche wie diesen funktioniert:

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

was die Karte ergibt:[0:0, 1:2, 2:4]

Wie wäre es mit so etwas?

// 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']
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top