2013-01-07 12 views
31

Voglio trovare una chiave specifica in una data mappa. Se viene trovata la chiave, voglio quindi ottenere il valore di quella chiave dalla mappa.groovy: trova una chiave in una mappa e restituisce il suo valore

Questo è quello che sono riuscito finora:

def mymap = [name:"Gromit", likes:"cheese", id:1234] 

def x = mymap.find{ it.key == "likes" } 

if(x) 
    println x.value 

Questo funziona, l'uscita è "cheese" come previsto. Grande, ma non voglio fare x.value alla fine, e non voglio fare if(x). Voglio che x contenga direttamente il valore in qualche modo.

non posso ottenere il valore direttamente nella x come questo:

def mymap = [name:"Gromit", likes:"cheese", id:1234] 

def x = mymap.find{ it.key == "likesZZZ" }.value 

println x 

A causa della chiusura ritrovamento è nullo in questo caso, questo si traduce in un Exception Null Pointer. Ovviamente, lo snippet di codice sopra riportato funziona quando it.key == "likes", ma non sono sicuro di trovare sempre la chiave di destinazione nella mappa.

Che è una via "groovier" sicuro di fare questo su una mappa:

  • Controllare se una mappa ha una data chiave,
  • E se è così, ottenere il valore di questa chiave

risposta

10
def mymap = [name:"Gromit", id:1234] 
def x = mymap.find{ it.key == "likes" }?.value 
if(x) 
    println "x value: ${x}" 

println x.getClass().name 

?. controlli per nulla e non crea un'eccezione in Groovy. Se la chiave non esiste, il risultato sarà un org.codehaus.groovy.runtime.NullObject.

+0

Fantastico. Questo è ancora più groovy della risposta originale che ho selezionato e si adatta meglio a ciò che stavo cercando. Marcare questa è la risposta. Grazie. – noumenon

+3

L'uso di una chiusura è molto costoso. Meglio usare 'def x = mymap.get (" likes ") ?. value 'lì, molto più efficiente –

46

L'intero punto di utilizzo di Maps è l'accesso diretto. Se si sa per certo che il valore di una mappa non sarà mai Groovy- false, allora si può fare questo:

def mymap = [name:"Gromit", likes:"cheese", id:1234] 
def key = "likes" 

if(mymap[key]) { 
    println mymap[key] 
} 

Tuttavia, se il valore potrebbe essere potenzialmente Groovy- false, si dovrebbe usare:

if(mymap.containsKey(key)) { 
    println mymap[key] 
} 

la soluzione più semplice, però, se si conosce il valore non sta per essere Groovy- false (o si può ignorare che), e si desidera un valore di default, è in questo modo:

def value = mymap[key] ?: "default" 

Tutte e tre queste soluzioni sono notevolmente più veloci dei tuoi esempi, perché non scandiscono l'intera mappa per le chiavi. Sfruttano il design HashMap (o LinkedHashMap) che rende l'accesso diretto alle chiavi quasi istantaneo.

+1

Grazie. Mi mancava totalmente il punto. – noumenon

+1

Se si desidera valori predefiniti, è possibile definire la mappa come 'def map = [:]. WithDefault {" Default "}'. Quindi non è necessario utilizzare l'operatore Elvis per il valore predefinito. Ovviamente questo aggiornerà anche la mappa, quindi se non lo vuoi, allora Elvis è la tua strada. – fish

+0

La chiave può anche essere citata con virgolette doppie, ad esempio \t \t intestazioni def = ["Content-Type": "application/json"] – webjockey

0

Il motivo per cui si ottiene un'eccezione Pointer nullo è perché nel secondo esempio non vi è alcun numero di suonerie simili aZZZ. Prova:

def mymap = [name:"Gromit", likes:"cheese", id:1234] 
def x = mymap.find{ it.key == "likes" }.value 
if(x) 
    println "x value: ${x}" 
+0

Come indicato nella domanda, non posso essere sicuro che la chiave sarà sempre nel mappa, quindi volevo un modo che funzionasse in sicurezza (senza eccezioni) anche se la chiave era o non era nella mappa. – noumenon

1

In generale, questo dipende da cosa contiene la mappa. Se ha valori nulli, le cose possono diventare complicate e deve essere usato containsKey(key) o get(key, default) per rilevare che l'elemento esiste realmente. In molti casi il codice può diventare più semplice è possibile definire un valore di default:

def mymap = [name:"Gromit", likes:"cheese", id:1234] 
def x1 = mymap.get('likes', '[nothing specified]') 
println "x value: ${x}" } 

Si noti inoltre che containsKey() o get() sono molto più veloce di creazione di una chiusura per controllare l'elemento mymap.find{ it.key == "likes" }.Usare la chiusura ha senso solo se davvero fai qualcosa di più complesso lì dentro. Potresti ad es. fare questo:

mymap.find{ // "it" is the default parameter 
    if (it.key != "likes") return false 
    println "x value: ${it.value}" 
    return true // stop searching 
} 

O con parametri espliciti:

mymap.find{ key,value -> 
    (key != "likes") return false 
    println "x value: ${value}" 
    return true // stop searching 
} 
Problemi correlati