English 中文(简体)
How to do numerical simulation with immutable data in Clojure?
原标题:

I m using Clojure and I need to run a small simulation. I have a vector of length n (n is usually between 10 and 100) that holds values. On each simulation round (maybe 1000 rounds together), one of the values in the vector is updated randomly. I guess I could do this by using an Java array and calling the aset method, but this would break the functional programming/immutability idiom.

Is there a more functional way to do this, or should I just go with the Java array?

最佳回答
(defn run-sim [arr num-iters update-fn]
 (if (zero? num-iters)
   arr
   (let [i (rand-int (count arr))
         x (update-fn)]
     (println "setting arr[" i "] to" x)
     (recur (assoc arr i x) (dec num-iters) update-fn))))

user> (run-sim [1 2 3 4 5 6 7 8 9 10] 10 #(rand-int 1000))
setting arr[ 8 ] to 167
setting arr[ 4 ] to 977
setting arr[ 5 ] to 810
setting arr[ 5 ] to 165
setting arr[ 3 ] to 486
setting arr[ 1 ] to 382
setting arr[ 4 ] to 792
setting arr[ 8 ] to 478
setting arr[ 4 ] to 144
setting arr[ 7 ] to 416
[1 382 3 486 144 165 7 416 478 10]

There s no shame in using a Java array if you need it though. Especially if you need it to go fast. Limit the array-mutation to the inside of your function (clone the input array and work on that maybe) and no one will be the wiser.

问题回答

Adding to Brian s answer: If you need more speed, you can also resort to transients.

(defn run-sim
  [vektor num-iters update-fn]
  (loop [vektor    (transient vektor)
         num-iters (int num-iters)]
    (if (zero? num-iters)
      (persistent! vektor)
      (let [i (rand-int (count vektor))
            x (update-fn)]
        (recur (assoc! vektor i x) (dec num-iters))))))

Lets first define a function which updates a random index in a vector with a new value. Note that the original vector is not changed, instead a new vector (with the updated value) is returned:

(defn f [xs]
  (let [r (java.util.Random.)
        i (.nextInt r (count xs))
        b (.nextBoolean r)]
    (assoc xs i ((if b inc dec) (xs i)))))

This function chooses an index and then it either increases or decreases the value at that index by 1. You must of course change this function to your needs.

Then it is a simple matter to compose this function with itself as many times you want to run the simulation:

user=> ((apply comp (repeat 1000 f)) [0 0 0 0 0 0 0])
[7 -4 7 6 10 0 -6]

It s not that Clojure won t let you change values, it s just a little more cumbersome.

(def vec-ref (ref my-vector))

(dosync (set! vec-ref (assoc my-vector index value))

to look at values in the changed vector, use @vec-ref.

Could be off in details - I m not near a REPL, unfortunately. But it should get you started.





相关问题
WordPress Data Storage Efficiency

I ve been asked to review a WordPress plugin of sorts and try to find ways of making it faster. The premise of this plugin is basically to store a bunch of users and shifts and appointments and ...

Convert a 2D array index into a 1D index

I have two arrays for a chess variant I am coding in java...I have a console version so far which represents the board as a 1D array (size is 32) but I am working on making a GUI for it and I want it ...

Convert an array of integers for use in a SQL "IN" clause

Surely there is a framework method that given an array of integers, strings etc converts them into a list that can be used in a SQL "IN" clause? e.g. int[] values = {1,2,3}; would go to "(1,2,3)"

Sorting twodimensional Array in AS3

So, i have a two-dimensional Array of ID s and vote count - voteArray[i][0] = ID, voteArray[i][1] = vote count I want the top 3 voted items to be displayed in different colors, so i have a 2nd Array -...

C++ Array Sort Me

Stuck on an array sorter. Have to sort numbers from largest to smallest. I m trying two loops (one nested in the other). Here s the code: int counter=0; // inner counter int counter2=0; // outer ...

PHP array callback functions for cleaning output

I have an array of output from a database. I am wondering what the cleanest way to filter the values is example array Array ( [0] => Array ( [title] => title 1 ...

Best practice of big javascript objects

sry for this imprecise topic name. I am querying a dataset a lot of times so using ajax request would end up in tons of http requests. For this reason I decided to use the json encode method to ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

热门标签