2013-01-23 4 views
6

Facendo seguito da questa domanda: Idiomatic clojure map lookup by keywordChe vantaggio c'è da usare 'get' invece di accedere a una mappa

ACCESSO utilizzando clojure può essere fatto in molti modi.

(def m {:a 1} 

(get m :a) ;; => 1 
(:a m) ;; => 1 
(m :a) ;; => 1 

So che uso principalmente il secondo modulo, e talvolta il terzo, raramente il primo. quali sono i vantaggi (velocità/componibilità) dell'utilizzo di ciascuno?

+1

Vedere le risposte alla domanda collegata. L'unica altra cosa che viene in mente per ottenere è la versione 3-arity (ottieni la chiave della mappa non trovata) dove ottieni (gioco di parole) per specificare un valore predefinito. –

+2

@ A.Webb È possibile specificare un valore predefinito per tutti e tre gli usi: '(: km default)' e '(m: k default)' funzionano entrambi, purché m non sia nullo ovviamente. – amalloy

+0

@amalloy Ah, bello, grazie per averlo fatto notare! –

risposta

3

Da the clojure web page vediamo che

mappe implementare IFN, per invoke() di un argomento (un tasto) con un secondo argomento opzionale (un valore predefinito), ovvero le mappe sono funzioni delle chiavi . nil chiavi e valori sono ok.

A volte è gratificante dare un'occhiata sotto i cofani di Clojure. Se si guarda a ciò che invoke assomiglia a una mappa, si vede questo:

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L196

Apparentemente chiama il metodo di una mappa valAt.

Se si guarda a ciò che la funzione get non quando viene chiamato con una mappa, questo è una chiamata a clojure.lang.RT.get, e questo in realtà si riduce alla stessa chiamata ad valAt per una mappa (mappe implementare iLookup perché sono Associatives):

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L634.

Lo stesso vale per una mappa chiamata con una chiave e un valore non trovato. Quindi, qual è il vantaggio? Dal momento che entrambi i modi si riducono praticamente allo stesso modo, in termini di prestazioni non direi nulla. È solo convenienza sintattica.

1

Non penso che ci sia una differenza di velocità, e anche se così fosse, sarebbe un dettaglio di implementazione.

Personalmente preferisco la seconda opzione (: a m) perché a volte rende il codice un po 'più facile all'occhio. Ad esempio, spesso devo scorrere una sequenza di mappe:

(def foo '({:a 1} {:a 2} {:a 3})) 

Se voglio filtrare tutti i valori di: a che ora può usare:

(map :a foo) 

Invece di

(map #(get % :a) foo) 

o

(map #(% :a) foo) 

Di Certo, questa è una questione di gusti personali.

2

È possibile passare get a partial ecc. Per creare HOF per i problemi con i dati, anche se spesso non vengono visualizzati.

user=> (def data {"a" 1 :b 2}) 
#'user/data 
user=> (map (partial get data) (keys data)) 
(1 2) 

Io uso la terza forma molto quando i dati sono stringhe come chiavi

+2

Questo non risolve veramente la domanda. Si potrebbe facilmente '(mappare i dati (dati delle chiavi))' per ottenere un equivalente di '(dati vals)'. – amalloy

+0

Il punto è che get può essere composto con funzioni di trasformazione delle funzioni per produrre una funzione di twiddling dei dati prima che la mappa dei dati sia disponibile. Questo esempio illustra questo punto isolatamente, ma in pratica viene combinato con altri vincoli specifici del problema. –

12

get è utile quando la mappa potrebbe essere nullo o non-a-carta, e la chiave potrebbe essere qualcosa di non-callable (cioè non una parola chiave)

(def m nil) 
(def k "some-key") 

(m k) => NullPointerException 
(k m) => ClassCastException java.lang.String cannot be cast to clojure.lang.IFn 

(get m k) => nil 
(get m :foo :default) => :default 
0

Per aggiungere alla lista, ottenere è utile anche quando si utilizza la filettatura macro -> ed è necessario accedere tramite un tasto che non è una parola chiave

(let [m {"a" :a}] (-> m (get "a")))

0

un vantaggio di utilizzare la parola chiave primo approccio è che è il modo più conciso di accedere il valore con un comportamento tollerante nel caso in cui la mappa sia nulla.

Problemi correlati