开发者

clojure for loop, store the values in a set or map

开发者 https://www.devze.com 2023-04-09 03:54 出处:网络
This one has been bothering m开发者_如何学Goe for a while now, How should we store a value in a set or map in a for loop?

This one has been bothering m开发者_如何学Goe for a while now, How should we store a value in a set or map in a for loop?

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

i know this will not work, but i want a functionality similar to this , where the set will finally contain [0 0] [0 1]...[0 9] [1 0]...[9 9]

Thanks


If I understand your question correctly you need to turn your expression inside-out:

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

The thing to realize here is that for returns a value (a lazy sequence) unlike for-loops in more imperative languages like Java and C.


Is this what you want?

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

And if you just want the list as a set:

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

You will end up with a set of pairs.


Generally when you want to return a set or a map or other 'single value' that isn't a seq from a 'repeated' generalized operation on a seq, using reduce is more idiomatic/straightforward than loop/recur, and for always returns a seq (not a set or map).

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

note that (for ..) here is only used to produce a seq containing all the values to compile into the single result set. Or, for example:

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


clojure has a several great systems for managing mutable state. in this case you may want an atom containing a set

your other options are:

  • a ref if more than one change needs to made (coordinated many threads)
  • a var if this will be single threaded (a var may work just as well here as an atom)
  • an agent if you wanted to set the value of s asynchronously

of course for returns a sequence already so you may just want

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


I think you can also use some transient data structure in this scenario.

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

Just a code sample, not tested.

0

精彩评论

暂无评论...
验证码 换一张
取 消