2013-03-26 20 views
10

Moje pytanie z Groovy Maps. Szukałem sposobu programowego dodania nowego wpisu do mapy Groovy bez nadpisywania bieżącego wpisu. Na przykładJak dodać wiele wpisów mapy Groovy bez nadpisywania bieżących wpisów?

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}" 
} 

Pierwszy przebieg produkuje tę mapę:
editsMap: [FlagId: 10001, FlagMnemonic: TRA, Akcja: przegląd]

Ale drugie przejście nadpisuje pierwszą przepustkę z: editsMap: [FlagId: 10002, FlagMnemonic: REB, Action: deny]

Co próbuję zrobić, to utworzyć wiele wpisów w ramach jednej mapy. Muszę moją mapę, aby wypełnić tak:

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] 

Raz mam zaludnionych moją mapę wtedy muszę być w stanie znaleźć pewne wartości w celu przetwarzania wiadomości. Wierzę, że mogę użyć czegoś w stylu:

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

, aby wykonać szybkie wyszukiwanie.

Czy ktoś może mi pomóc zrozumieć, jak programowo dodawać wartości do mapy Groovy bez nadpisywania wartości już na mapie?

Odpowiedz

0

Musisz umieścić to w klasie, a następnie dodać tę klasę do mapy. Z tego co widzę twoje informacje związane jest więc posiadanie klasy do sklepu sens chyba brakuje mi niczego

Co można zrobić, to określić swoją klasę jako

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

mapie jest zbiorem keystone odwzorowania wartości, można przypisać różne wartości według klucza, aby można było użyć klucza, aby znaleźć je później. Twój przykład polega na wielokrotnym wprowadzaniu wartości dla tych samych kluczy. Musisz wybrać unikalne klucze.

Zrób jakąś klasę do przechowywania wartości dla jednego wpisu na mapie:

class Stuff { 
    String flagMnemonic 
    String action 
} 

zrobić mapę, gdzie można korzystać z flagId jako klucz (bo to, w jaki sposób zidentyfikować flagę jednoznacznie) i rzeczy jako wartość (ponieważ są to dane, które chcesz wyszukać).

def editsMap = [:] 

Jeśli użyto deklaracje typu tutaj, a jeśli flagId jest String typ mapie byłoby Map<String, Stuff>.

Teraz można umieścić rzeczy na mapie:

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

i dostać go z powrotem z

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

Również nie jest to łatwe alternatywą dla korzystania ?: "default" ustawić wartości domyślne, można użyć withDefault podczas tworzenia mapy:

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

dzięki czemu za każdym razem, gdy k dla czegoś z mapy, która tam nie jest, otrzymujesz określony obiekt domyślny.

4

Można też zrobić coś takiego:

// 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

Chcesz coś 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 sprawia czystą Groovy emulację Multimap:

class GroovyMultimap { 
    Map map = [:] 

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

Można użyj putAt i getAt dla synt cukier atycki w operacjach na mapie. Możesz również wypróbować obiekt mixin w obiekcie mapy.

również korzysta on z Groovy multimapy guawy za:

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

Możesz także wykonać: '[:]. WithDefault {[]} .z {map -> map.fruit << 'banana'; map.fruit << "jabłko"; map.veg << marchewka; mapa} ' –

7

I natknąłem się na to kilka lat temu jako odpowiedź na podobne pytanie w innym miejscu. Nie mogę znaleźć skąd pochodzi, więc jeśli ktokolwiek zna źródło, proszę to opublikować tutaj.

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(",") 
} 

otrzymujemy:

a -> 1,2,3 

Zastosowanie wtryskiwanego multiPut() sposób nie magiczne.

1

Jeśli chcesz zrobić obiekt typu multimap bez klas zewnętrznych, możesz po prostu zapisać mapę list zamiast, składnia nie będzie uciążliwa ani nic.

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}" } lub jeśli naprawdę korzystne oryginalną składnię to będzie wyglądać: editsMap.get('FlagId').add(lineEdits_Flag.id) lub nawet to powinno działać: editsMap.get('FlagId') << lineEdits_Flag.id Zaletą tego rozwiązania jest to, że wydaje się być bardziej oczywiste, co robisz .. na przykład nie jest to magiczna mapa, która konwertuje pojedyncze elementy do listy (która nie jest standardową umową mapową), ale zawsze jest mapą list, którą po prostu używasz jako mapę list.

.get będzie zawsze działał w ten sam sposób, w jaki została opisana multimapa - zawsze zwróci listę dla tego elementu na mapie.

Powiązane problemy