2013-03-26 10 views
10

La mia domanda con Groovy Maps. Ho cercato un modo per aggiungere una nuova voce a una mappa Groovy a livello di programmazione senza sovrascrivere la voce corrente. Per esempioCome si aggiungono più voci della mappa Groovy senza sovrascrivere le voci correnti?

def editsMap = [:] 

lineEdits.flag.each 
{ lineEdits_Flag -> 
    editsMap.put('FlagId',lineEdits_Flag.id) 
    editsMap.put('FlagMnemonic',lineEdits_Flag.mnemonic) 
    editsMap.put('Action',lineEdits_Flag.action) 
    println "editsMap: ${editsMap}" 
} 

Il primo passaggio produce questa mappa:
editsMap: [FlagId: 10001, FlagMnemonic: TRA, Azione: rassegna]

Ma il secondo passaggio sovrascrive il primo passaggio con: editsMap: [FlagId: 10002, FlagMnemonic: REB, Azione: deny]

Quello che sto cercando di fare è creare più voci all'interno di una mappa. Ho bisogno della mia carta per popolare qualcosa di simile:

editsMap: [FlagId:10001, FlagMnemonic:TRA, Action:review] 
editsMap: [FlagId:10002, FlagMnemonic:REB, Action:deny] 
editsMap: [FlagId:10003, FlagMnemonic:UNB, Action:deny] 
editsMap: [FlagId:20001, FlagMnemonic:REB, Action:deny] 
editsMap: [FlagId:20002, FlagMnemonic:ICD, Action:review] 
editsMap: [FlagId:30001, FlagMnemonic:REB, Action:deny] 
editsMap: [FlagId:40001, FlagMnemonic:ICD, Action:review] 
editsMap: [FlagId:40002, FlagMnemonic:MPR, Action:review] 
editsMap: [FlagId:50001, FlagMnemonic:CPT, Action:deny] 
editsMap: [FlagId:60001, FlagMnemonic:DTU, Action:deny] 
editsMap: [FlagId:70001, FlagMnemonic:ICD, Action:review] 
editsMap: [FlagId:70002, FlagMnemonic:MPR, Action:review] 

Una volta che ho popolato la mia mappa quindi ho bisogno di essere in grado di trovare certi valori, al fine di elaborare un messaggio. Credo di poter usare qualcosa del tipo:

def thisValue = appliedEditsMap[FlagId, '10001'] ?: "default" 

per fare una rapida occhiata.

Qualcuno può aiutarmi a capire come aggiungere valori a una mappa Groovy in modo programmatico senza sovrascrivere i valori già presenti nella mappa?

risposta

0

È necessario inserire questo in una classe e aggiungere tale classe alla mappa. Da quello che vedo i tuoi dati è correlato in modo da avere una classe per negozio ha senso a meno che non mi manca nulla

Che cosa si può fare è definire la classe come

class Flag { 

String flagID 
String flagMnemonic 
String action 
} 

Now Put your Flag in to your map as 

editsMap.put(10000,newFlag(flagID:'10000',flagMnemonic:'TES',action:'tes')) 
2

Una mappa è un insieme di chiave- mappatura dei valori, si inseriscono valori diversi per chiave in modo da poter utilizzare la chiave per trovarli in un secondo momento. Il tuo esempio è collegare continuamente i valori per gli stessi tasti. Devi scegliere chiavi uniche.

Fare qualche classe per memorizzare i valori per una voce nella mappa:

class Stuff { 
    String flagMnemonic 
    String action 
} 

fare una mappa dove si desidera utilizzare flagId come chiave (perché è così che si identifica la bandiera in modo univoco) e roba come il valore (perché sono i dati che si desidera cercare).

def editsMap = [:] 

se è stato utilizzato dichiarazioni di tipo qui, e se flagId è una stringa, il tipo di carta sarebbe Map<String, Stuff>.

Ora si può mettere roba nella mappa:

lineEdits.flag.each { lineEdits_Flag -> 
    editsMap[lineEdits_Flag.id] = 
    new Stuff(
     flagMnemonic: lineEdits_Flag.mnemonic, 
     action: lineEdits_Flag.action) 
} 

e ottenere di nuovo fuori con

def myStuffFor10001 = editsMap['10001'] 
println myStuffFor10001.flagMnemonic // should equal 'TRA' 
println myStuffFor10001.action // should equal 'review' 

Inoltre c'è un facile alternativa all'utilizzo ?: "default" per impostare i valori di default, è possibile utilizzare withDefault quando si crea la tua mappa:

def defaultStuff = new Stuff(
    flagMnemonic: "defaultMnemonic", action:"defaultAction") 
def editsMap = [:].withDefault { defaultStuff } 

in modo che ogni volta che come k per qualcosa dalla mappa che non è presente, ottieni l'oggetto predefinito specificato.

4

Si potrebbe anche fare qualcosa di simile:

// Dummy map for testing 
lineEdits = [ flag:[ 
    [id:10001, mnemonic:'TRA', action:'review'], 
    [id:10002, mnemonic:'REB', action:'deny'], 
    [id:10003, mnemonic:'UNB', action:'deny'], 
    [id:20001, mnemonic:'REB', action:'deny'], 
    [id:20002, mnemonic:'ICD', action:'review'], 
    [id:30001, mnemonic:'REB', action:'deny'], 
    [id:40001, mnemonic:'ICD', action:'review'], 
    [id:40002, mnemonic:'MPR', action:'review'], 
    [id:50001, mnemonic:'CPT', action:'deny'], 
    [id:60001, mnemonic:'DTU', action:'deny'], 
    [id:70001, mnemonic:'ICD', action:'review'], 
    [id:70002, mnemonic:'MPR', action:'review'] ] ] 

def editsMap = lineEdits.flag 
         .groupBy { it.id } // Group by id 
         .collectEntries { k, v -> 
          [ k, v[ 0 ] ] // Just grab the first one (flatten) 
         } 

assert editsMap[ 60001 ] == [ id:60001, mnemonic:'DTU', action:'deny' ] 
9

si desidera qualcosa di simile Guava's MultiMap:

Multimap<String, String> myMultimap = ArrayListMultimap.create(); 

// Adding some key/value 
myMultimap.put("Fruits", "Bannana"); 
myMultimap.put("Fruits", "Apple"); 
myMultimap.put("Fruits", "Pear"); 
myMultimap.put("Vegetables", "Carrot"); 

// Getting values 
Collection<string> fruits = myMultimap.get("Fruits"); 
System.out.println(fruits); // [Bannana, Apple, Pear] 

This guy rende un'emulazione Groovy pura di Multimap:

class GroovyMultimap { 
    Map map = [:] 

    public boolean put(Object key, Object value) { 
     List list = map.get(key, []) 
     list.add(value) 
     map."$key" = list 
    } 
} 

Puoi utilizzare putAt e getAt per la sincronizzazione zucchero atomico nelle operazioni cartografiche. Puoi anche provare un mixin in un oggetto di mappa.

Usa anche Groovy con multimap di Guava:

List properties = ['value1', 'value2', 'value3'] 
Multimap multimap = list.inject(LinkedListMultimap.create()) { 
    Multimap map, object -> 
    properties.each { 
     map.put(it, object."$it") 
    } 
    map 
} 
properties.each { 
    assertEquals (multimap.get(it), list."$it") 
} 
+4

È anche possibile eseguire: '[:]. ConDefault {[]} .with {map -> map.fruit << 'banana'; map.fruit << 'apple'; map.veg << 'carota'; mappa} ' –

7

mi sono imbattuto in questo diversi anni fa come una risposta a una domanda simile su un altro sito. Non riesco a trovare da dove provenga, quindi se qualcuno conosce la fonte, per favore, postala qui.

LinkedHashMap.metaClass.multiPut << { key, value -> 
    delegate[key] = delegate[key] ?: []; delegate[key] += value 
} 

def myMap = [:] 

myMap.multiPut("a", "1") 
myMap.multiPut("a", "2") 
myMap.multiPut("a", "3") 

myMap.each {key, list -> 
    println "${key} -> $value.list(",") 
} 

esprime:

a -> 1,2,3 

L'uso del iniettato multiPut() metodo fa la magia.

1

Se vuoi fare la cosa multimap senza classi esterne, puoi semplicemente memorizzare una mappa di liste, la sintassi non sarà ingombrante o altro.

def editsMap = [:].withDefault{[]} lineEdits.flag.each { lineEdits_Flag -> editsMap.FlagId << lineEdits_Flag.id editsMap.FlagMnemonic << lineEdits_Flag.mnemonic editsMap.Action << lineEdits_Flag.action println "editsMap: ${editsMap}" } o se davvero preferito la sintassi originale sarebbe assomigliare: editsMap.get('FlagId').add(lineEdits_Flag.id) o anche questo dovrebbe funzionare: editsMap.get('FlagId') << lineEdits_Flag.id Il vantaggio di questa soluzione è che tende ad essere più evidente che cosa si sta facendo .. Ad esempio, non è una mappa magica che converte singoli elementi in una lista (che non è il contratto standard della mappa) ma è sempre una mappa di elenchi che viene semplicemente utilizzata come una mappa di elenchi.

Il file .get funzionerà sempre allo stesso modo in cui è stata descritta la multimap: restituirà sempre l'elenco per quell'elemento nella mappa.

Problemi correlati