2011-09-29 7 views
7

Questo mi ha infastidito da un po 'ora, Come dovremmo memorizzare un valore in un set o in una mappa in un ciclo for?clojure per loop, memorizza i valori in un set o mappa

(let [s #{}] 
    (for [ i (range 10) 
      j (range 10) ] 
     (into s [i j]))) 

so che questo non funzionerà, ma voglio una funzionalità simile a questo, in cui l'insieme sarà finalmente conterrà [0 0] [0 1] ... [0 9] [1 0] .. . [9 9]

Grazie

+0

Grazie a tutti, per le risposte. – KaKa

risposta

13

Se ho capito la tua domanda correttamente è necessario per trasformare la vostra espressione inside-out:

(let [s #{}] 
    (into s (for [i (range 10) 
       j (range 10)] 
      [i j]))) 

La cosa da capire qui è che for restituisce un valore (una sequenza lenta) a differenza dei cicli for in lingue più imperative come Java e C.

0

clojure ha un diversi grandi sistemi per la gestione di stato mutevole. in questo caso si consiglia un atom contenente una serie

le altre opzioni sono:

  • un ref se più di un cambiamento deve fatti (tanti fili coordinati)
  • un var se questo sarà thread singolo (una var può funzionare altrettanto bene qui come un atomo)
  • un agent se si vuole impostare il valore di s asincrono

naturalmente for restituisce una sequenza già così si può fare,

(into #{} (for [ i (range 10) 
        j (range 10) ] 
      [i j])) 
+0

Il primo frammento di codice qui non ha senso, per quanto ne so? Non è un modo valido per usare "swap!", E come più tardi citi non è comunque una buona idea. – amalloy

+0

il primo snipit non è stato davvero il punto della risposta, quindi l'ho appena rimosso. posa senza test * tisk tisk * –

6

È questo quello che vuoi?

(into #{} (for [i (range 10) j (range 10)] 
    [i j])) 
;-> #{[2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [1 0] 
;  [2 2] [3 3] [4 4] [5 5] [6 6]... 

E se si desidera solo l'elenco come un insieme:

(set (for [i (range 10) j (range 10)] 
    [i j]))  

Vi ritroverete con un insieme di coppie.

5

genere quando si desidera restituire un set o una mappa o altro 'valore singolo' che non è un ss da un'operazione generalizzata 'ripetuta' su un ss, utilizzando reduce è più idiomatica/semplice di loop/recur, e for restituisce sempre un seq (non un set o una mappa).

(reduce conj #{} (for [i (range 10) j (range 10)] [i j])) 

nota che (per ..) qui viene utilizzato solo per produrre un seq contenente tutti i valori per compilare nel singolo risultato set. Oppure, ad esempio:

(reduce + 0 (range 100)) 
=> 4950 
0

Penso che in questo scenario si possa utilizzare anche una struttura di dati transitoria.

(let [s (transient #{})] 
(for [ i (range 10) 
     j (range 10) ] 
    (assoc! s i j))) 
(persistent! s) 

Solo un esempio di codice, non testato.

+1

Questo non è corretto. Da [docs for transients] (http://clojure.org/transients): "Si noti in particolare che i transitori non sono progettati per essere localizzati sul posto. È necessario acquisire e utilizzare il valore restituito nella prossima chiamata. modo, supportano la stessa struttura di codice del codice persistente funzionale che sostituiscono ". – Jonas