2011-09-29 7 views
7

Ten od jakiegoś czasu mnie dręczy, Jak przechowywać wartość w zbiorze lub mapie w pętli for?clojure dla pętli, przechowuj wartości w zbiorze lub mapie

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

wiem, że to nie będzie działać, ale chcę mieć funkcjonalność podobną do tego, gdzie zestaw będzie zawierał wreszcie [0 0] [0 1] ... [0 9] [1 0] .. . [9 9]

Dzięki

+0

Dziękuję wszystkim za odpowiedzi. – KaKa

Odpowiedz

13

Jeśli dobrze rozumiem Twoje pytanie trzeba włączyć swoją ekspresję inside-out:

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

Rzecz zrealizować tutaj jest że for zwraca wartość (leniwą sekwencję) w przeciwieństwie do pętli for w bardziej niezbędnych językach, takich jak Java i C.

0

clojure ma kilka wielkich systemów zarządzania stan zmienny. w tym przypadku może chcesz atom zawierający zestaw

Twoje inne opcje:

  • się ref jeśli więcej niż jedna zmiana musi wykonany (Coordinated wiele wątków)
  • var jeśli będzie to pojedynczy gwintowany (a var może działać tak samo dobrze jak tu atomu)
  • agent jeśli chcieli ustawić wartość s asynchronicznie

oczywiście for zwraca sekwencję już więc może po prostu chcesz

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

Pierwszy fragment kodu tutaj nie ma żadnego sensu, o ile mogę powiedzieć? To nie jest prawidłowy sposób użycia 'swap!' I jak później wspomniałeś, to i tak nie jest dobry pomysł. – amalloy

+0

Pierwszy snipit nie był tak naprawdę punktem odpowiedzi, więc po prostu go usunąłem. pozowanie bez testowania * tisk tisk * –

6

Czy tego chcesz?

(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]... 

A jeśli chcesz po prostu listę jako zestaw:

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

Będziesz skończyć z zestawem par.

5

Ogólnie gdy chcesz powrócić zestawu lub mapę lub inne „” pojedynczą wartość, która nie jest nast od „powtarzająca się” uogólnionego działania na nast korzystając reduce jest bardziej idiomatyczne/prostolinijny niż loop/recur, i for zawsze zwraca seq (nie zbiór lub mapę).

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

uwaga, że ​​(dla ..) tutaj jest używana tylko do produkcji nast zawierającą wszystkie wartości skompilować do pojedynczego wyniku ustawiony. Lub na przykład:

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

Myślę, że w tym scenariuszu można również użyć przejściowej struktury danych.

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

Tylko próbka kodu, nie testowana.

+1

To nie jest poprawne. Z [the docs for transients] (http://clojure.org/transients): "Zwróćcie uwagę w szczególności, że transjenty nie są zaprojektowane w taki sposób, aby były wycinane w miejscu, ale należy przechwycić i wykorzystać wartość zwracaną w następnym wywołaniu. sposób, obsługują tę samą strukturę kodu co funkcjonalny, stały kod, który zastępują ". – Jonas

Powiązane problemy